1006 lines
29 KiB
Markdown
1006 lines
29 KiB
Markdown
---
|
|
name: kelp-ui
|
|
description: Frontend development with Kelp UI (v1.17.2): an HTML-first UI library using HUG CSS, light-DOM web components, and cascade layers with no build step. Complete component, layout, and utility reference with HTML examples, progressive enhancement patterns, and anti-patterns to prevent framework-style mistakes
|
|
---
|
|
|
|
## Role
|
|
|
|
Act as a Senior Frontend Developer specializing in Kelp UI. Generate, review, and guide HTML implementation using Kelp's HTML-first approach. Always produce semantic, progressively enhanced HTML that follows Kelp's HUG CSS methodology — classless first, utilities to nudge, group classes for complex components.
|
|
|
|
## When to Use
|
|
|
|
- Building UI with Kelp UI library
|
|
- Reviewing existing HTML for Kelp best practices and anti-patterns
|
|
- Choosing between similar Kelp components or layouts
|
|
- Customizing a Kelp theme (CSS variables, cascade layers)
|
|
- Debugging Kelp component behavior
|
|
- Implementing progressive enhancement patterns with Kelp web components
|
|
|
|
## Version Awareness
|
|
|
|
This skill was built against **Kelp UI v1.17.2**.
|
|
|
|
- When uncertain about a feature, attribute, or component, use WebFetch to check `https://kelpui.com/docs` for the current documentation
|
|
- Flag when a recommendation might be version-dependent
|
|
- The source of truth is always `kelpui.com/docs`, not any local repository
|
|
|
|
---
|
|
|
|
## Core Principles
|
|
|
|
These 6 rules govern every decision when working with Kelp. Violating any of them is an anti-pattern.
|
|
|
|
### 1. HTML First (HUG CSS)
|
|
|
|
Kelp uses a **H**TML > **U**tility > **G**roup approach:
|
|
|
|
1. **Classless HTML** for core styles — bare `<h1>`, `<p>`, `<button>`, `<input>` are styled without any classes
|
|
2. **Utility classes** to nudge and tweak when needed — `.secondary`, `.subtle`, `.size-l`
|
|
3. **Group classes** for complex components — `.callout`, `.split`, `.grid`
|
|
|
|
```html
|
|
<!-- Good: classless HTML, styled by default -->
|
|
<h1>Hello world!</h1>
|
|
<p>How are you today?</p>
|
|
<button>Say Hi</button>
|
|
|
|
<!-- Good: utility classes to nudge -->
|
|
<button class="secondary subtle">Say Hi</button>
|
|
```
|
|
|
|
### 2. Progressive Enhancement
|
|
|
|
Web components enhance content that is already usable without JavaScript.
|
|
|
|
```html
|
|
<!-- Before JS loads: user sees "1295" -->
|
|
<!-- After JS loads: user sees "$1,295" -->
|
|
This costs
|
|
<format-number type="currency">
|
|
1295
|
|
</format-number>.
|
|
```
|
|
|
|
Content must always be accessible before JavaScript runs.
|
|
|
|
### 3. Light DOM Only
|
|
|
|
Kelp web components use the **light DOM exclusively**. No Shadow DOM, ever. This means standard CSS applies, no style encapsulation barriers, and the DOM is inspectable.
|
|
|
|
### 4. No Build Step Required
|
|
|
|
Kelp uses modern HTML, CSS, and JavaScript natively. Everything is customizable with CSS variables and HTML attributes. No Vite, Webpack, Rollup, or any bundler required.
|
|
|
|
You *can* use a build step if the project already has one, but you never *need* one.
|
|
|
|
### 5. Cascade Layers for Customization
|
|
|
|
Kelp uses CSS `@layer` to control cascade order:
|
|
|
|
- **`kelp`** — parent layer. Code outside this layer takes priority automatically.
|
|
- **`kelp.theme`** — customize colors, fonts, sizes, breakpoints
|
|
- **`kelp.extend`** — add new features, customize existing components
|
|
- **`kelp.helpers`** — add or customize utility classes
|
|
- **`kelp.effects`** — add or override state-based effects (`:hover`, `:active`)
|
|
|
|
CSS outside the `kelp` layer always wins, making overrides simple without specificity battles.
|
|
|
|
### 6. Semantic HTML is the Component
|
|
|
|
Use native HTML elements first. A `<nav>` is a nav, a `<button>` is a button, a `<dialog>` is a dialog. Never wrap semantic elements in meaningless `<div>`s or recreate native behavior with JavaScript.
|
|
|
|
---
|
|
|
|
## CSS Architecture
|
|
|
|
### Loading
|
|
|
|
Always use `<link>` tags. Never `@import`.
|
|
|
|
```html
|
|
<!-- CDN -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kelpui@1/css/kelp.css">
|
|
<script type="module" src="https://cdn.jsdelivr.net/npm/kelpui@1/js/kelp.js"></script>
|
|
|
|
<!-- Local -->
|
|
<link rel="stylesheet" href="./css/kelp.css">
|
|
<script type="module" src="./js/kelp.js"></script>
|
|
```
|
|
|
|
### Starter HTML
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en-us">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Page Title</title>
|
|
<link rel="stylesheet" href="./css/kelp.css">
|
|
</head>
|
|
<body>
|
|
<main class="container">
|
|
<h1>Hello World</h1>
|
|
</main>
|
|
</body>
|
|
<script type="module" src="./js/kelp.js"></script>
|
|
</html>
|
|
```
|
|
|
|
### Cascade Layers
|
|
|
|
```
|
|
kelp (parent — everything inside)
|
|
├── kelp.theme — colors, fonts, sizes, breakpoints
|
|
├── kelp.extend — new features, component customization
|
|
├── kelp.helpers — utility class customization
|
|
└── kelp.effects — state-based effects (:hover, :active)
|
|
```
|
|
|
|
Code outside the `kelp` layer overrides everything inside it.
|
|
|
|
**Do not use** internal Kelp layers — they can change without notice.
|
|
|
|
### Custom Theme Pattern
|
|
|
|
Create a `kelp.custom.css` file and wrap overrides in the appropriate layer:
|
|
|
|
```css
|
|
@layer kelp.theme {
|
|
:root {
|
|
--font-primary: "Source Sans Pro", sans-serif;
|
|
--font-secondary: "Playfair Display", serif;
|
|
--font-size-base: 112.5%;
|
|
}
|
|
}
|
|
```
|
|
|
|
### CSS Variables Reference
|
|
|
|
**Fonts:**
|
|
|
|
| Variable | Default | Usage |
|
|
|----------|---------|-------|
|
|
| `--font-primary` | Sans serif stack | Body text, most elements |
|
|
| `--font-secondary` | Serif stack | Headings |
|
|
| `--font-monospace` | Monospace stack | Code snippets |
|
|
|
|
**Breakpoints:**
|
|
|
|
| Variable | Size |
|
|
|----------|------|
|
|
| `--breakpoint-xs` | `18em` |
|
|
| `--breakpoint-s` | `28em` |
|
|
| `--breakpoint-m` | `38em` |
|
|
| `--breakpoint-l` | `52em` |
|
|
| `--breakpoint-xl` | `60em` |
|
|
| `--breakpoint-2xl` | `80em` |
|
|
|
|
Note: CSS variables cannot be used in `@media` queries. These are used for element sizing (e.g., `container-*` max-widths).
|
|
|
|
**Size Scale** (em-based, scales with font-size):
|
|
|
|
| Variable | Size | px Equiv |
|
|
|----------|------|----------|
|
|
| `--size-6xs` | `0.125em` | 2px |
|
|
| `--size-5xs` | `0.25em` | 4px |
|
|
| `--size-4xs` | `0.5em` | 8px |
|
|
| `--size-3xs` | `0.6875em` | 11px |
|
|
| `--size-2xs` | `0.75em` | 12px |
|
|
| `--size-xs` | `0.8125em` | 13px |
|
|
| `--size-s` | `0.9375em` | 15px |
|
|
| `--size-m` | `1em` | 16px |
|
|
| `--size-l` | `1.0625em` | 17px |
|
|
| `--size-xl` | `1.1875em` | 19px |
|
|
| `--size-2xl` | `1.3125em` | 21px |
|
|
| `--size-3xl` | `1.5em` | 24px |
|
|
| `--size-4xl` | `1.75em` | 28px |
|
|
| `--size-5xl` | `2em` | 32px |
|
|
| `--size-6xl` | `3em` | 48px |
|
|
|
|
`--space` = `1.5em` (matches default line-height, used for margins and padding).
|
|
|
|
`--font-size-base` = `112.5%` (18px default). Changing this scales the entire UI.
|
|
|
|
**Border Radius:**
|
|
|
|
| Variable | Size |
|
|
|----------|------|
|
|
| `--border-radius-s` | `0.25em` |
|
|
| `--border-radius-m` | `0.5em` |
|
|
| `--border-radius-l` | `1.3125em` |
|
|
| `--border-radius-circle` | `50%` |
|
|
|
|
**Line Heights:**
|
|
|
|
| Variable | Value |
|
|
|----------|-------|
|
|
| `--line-height-xs` | `1.2` |
|
|
| `--line-height-s` | `1.4` |
|
|
| `--line-height-m` | `1.5` (default) |
|
|
|
|
**Component Color Variables** (used by all components):
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `--background-color` | Background (+ `-hover`, `-active`) |
|
|
| `--border-color` | Border (+ `-hover`, `-active`) |
|
|
| `--color` | Text color (+ `-hover`, `-active`) |
|
|
|
|
These use semantic color variables (`--color-fill-muted`, `--color-on-muted`, etc.) as values. Utility classes like `.primary`, `.secondary`, `.success`, `.danger` adjust them.
|
|
|
|
**Focus Ring:**
|
|
|
|
| Variable | Default |
|
|
|----------|---------|
|
|
| `--focus-ring-color` | `--color-blue-50` (light) / `--color-blue-60` (dark) |
|
|
| `--focus-ring-style` | `solid` |
|
|
| `--focus-ring-width` | `--size-6xs` |
|
|
| `--focus-ring-offset` | `--size-6xs` |
|
|
|
|
Kelp uses `:focus-visible` — focus rings appear only on keyboard navigation.
|
|
|
|
### Dark Mode
|
|
|
|
Class-based, not media-query-based. This is intentional — it provides more flexibility.
|
|
|
|
```html
|
|
<!-- Entire site dark -->
|
|
<body class="dark">...</body>
|
|
|
|
<!-- Section overrides -->
|
|
<body class="dark">
|
|
<div class="light">This section is light</div>
|
|
</body>
|
|
|
|
<!-- No class = light by default -->
|
|
<body>...</body>
|
|
```
|
|
|
|
Auto-detect from OS settings — load this script in `<head>`:
|
|
|
|
```html
|
|
<script src="https://cdn.jsdelivr.net/npm/kelpui@1/js/dark-mode-auto.js"></script>
|
|
```
|
|
|
|
---
|
|
|
|
## Layout Reference
|
|
|
|
### Choosing a Layout
|
|
|
|
| Need | Layout | Class |
|
|
|------|--------|-------|
|
|
| Two items pushed to opposite edges | Split | `.split` |
|
|
| One fixed-width + one fluid item | Sidecar | `.sidecar` / `.sidecar-end` |
|
|
| Multi-column with explicit proportions | Grid | `.grid` + `.item-*` |
|
|
| Equal-width auto-columns | Grid auto | `.grid-auto` |
|
|
| Horizontal wrapping list of items | Cluster | `.cluster` |
|
|
| Vertical stack with consistent spacing | Stack | `.stack` |
|
|
| Constrain content width | Container | `.container-*` |
|
|
| Readable text column | Text | `.text` |
|
|
| Title + actions in a row | Action Header | `.action-header` |
|
|
|
|
### Container
|
|
|
|
Constrains content to a max-width. Uses breakpoint variables.
|
|
|
|
```html
|
|
<div class="container">Full width up to default max</div>
|
|
<div class="container-s">Small container (28em)</div>
|
|
<div class="container-m">Medium container (38em)</div>
|
|
<div class="container-l">Large container (52em)</div>
|
|
<div class="container-xl">Extra large container (60em)</div>
|
|
```
|
|
|
|
### Grid
|
|
|
|
12-column CSS Grid with fraction-based sizing.
|
|
|
|
```html
|
|
<!-- Two-column layout -->
|
|
<div class="grid">
|
|
<div class="item-third">Sidebar (4/12)</div>
|
|
<div class="item-two-thirds">Main content (8/12)</div>
|
|
</div>
|
|
|
|
<!-- Responsive: stack on mobile, columns on medium+ -->
|
|
<div class="grid grid-m">
|
|
<div class="item-half">Left</div>
|
|
<div class="item-half">Right</div>
|
|
</div>
|
|
|
|
<!-- Auto-grid: equal-width columns based on --width -->
|
|
<div class="grid-auto">
|
|
<div>Card 1</div>
|
|
<div>Card 2</div>
|
|
<div>Card 3</div>
|
|
</div>
|
|
```
|
|
|
|
Column sizes: `.item-fourth` (3/12), `.item-third` (4/12), `.item-half` (6/12), `.item-two-thirds` (8/12), `.item-three-fourths` (9/12).
|
|
|
|
Responsive breakpoints: `.grid-s` (28em), `.grid-m` (32em), `.grid-l` (52em), `.grid-xl` (60em).
|
|
|
|
Content choreography: `.start-first`, `.start-third`, `.start-two-thirds` for reordering.
|
|
|
|
### Cluster
|
|
|
|
Horizontal wrapping group with consistent gap.
|
|
|
|
```html
|
|
<div class="cluster">
|
|
<span>Tag 1</span>
|
|
<span>Tag 2</span>
|
|
<span>Tag 3</span>
|
|
</div>
|
|
```
|
|
|
|
### Split
|
|
|
|
Push items to opposite edges.
|
|
|
|
```html
|
|
<!-- Horizontal: logo left, nav right -->
|
|
<div class="split">
|
|
<div>Logo</div>
|
|
<nav>Links</nav>
|
|
</div>
|
|
|
|
<!-- Vertical split -->
|
|
<div class="split direction-column">
|
|
<div>Top</div>
|
|
<div>Bottom</div>
|
|
</div>
|
|
```
|
|
|
|
Items keep their natural width. Use for navbars, header rows, footer bars.
|
|
|
|
### Sidecar
|
|
|
|
One item fixed-width, the other fills remaining space.
|
|
|
|
```html
|
|
<!-- First item fixed, second fluid -->
|
|
<div class="sidecar">
|
|
<img src="avatar.jpg" alt="Avatar">
|
|
<div>Content fills remaining space</div>
|
|
</div>
|
|
|
|
<!-- Second item fixed, first fluid -->
|
|
<div class="sidecar-end">
|
|
<div>Content fills remaining space</div>
|
|
<button>Action</button>
|
|
</div>
|
|
```
|
|
|
|
Use for: icon + text, avatar + content, search field + button, sidebar + main.
|
|
|
|
**Split vs Sidecar:** Split pushes items apart with space between (both keep natural width). Sidecar makes one item grow to fill space (asymmetric).
|
|
|
|
### Stack
|
|
|
|
Vertical stack with consistent spacing between children.
|
|
|
|
```html
|
|
<div class="stack">
|
|
<h2>Section Title</h2>
|
|
<p>Content paragraph.</p>
|
|
<button>Action</button>
|
|
</div>
|
|
```
|
|
|
|
### Text
|
|
|
|
Sets optimal line length for readable text.
|
|
|
|
```html
|
|
<div class="text">
|
|
<p>Long paragraph of readable content...</p>
|
|
</div>
|
|
```
|
|
|
|
### Action Header
|
|
|
|
Title + actions in a row, with title taking priority.
|
|
|
|
```html
|
|
<div class="action-header">
|
|
<h2>Page Title</h2>
|
|
<div class="cluster">
|
|
<button>Edit</button>
|
|
<button class="danger">Delete</button>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Component Reference
|
|
|
|
### Typography
|
|
|
|
**Headings** — classless `<h1>` through `<h6>`. Styled automatically. Never add heading classes.
|
|
|
|
**Text** — classless `<p>`, `<strong>`, `<em>`, `<mark>`, `<small>`, `<del>`, `<ins>`, `<sub>`, `<sup>`. All styled.
|
|
|
|
**Links** — classless `<a>`. Styled with dotted underline by default.
|
|
|
|
**Blockquotes** — classless `<blockquote>`. Use `<cite>` for attribution.
|
|
|
|
**Code** — classless `<code>` for inline, `<pre><code>` for blocks.
|
|
|
|
**Lists** — classless `<ul>`, `<ol>`, `<dl>`. Nested lists supported.
|
|
|
|
**Dividers** — classless `<hr>`.
|
|
|
|
### Content
|
|
|
|
**Badges** — `<span class="badge">`. Modifiers: `.primary`, `.secondary`, `.success`, `.danger`, `.warning`.
|
|
|
|
**Avatar** — `<img class="avatar">`. Modifiers: `.size-s`, `.size-l`, `.size-xl`.
|
|
|
|
**Callouts** — `<div class="callout">`. Modifiers: `.primary`, `.secondary`, `.success`, `.danger`, `.warning`.
|
|
|
|
```html
|
|
<div class="callout warning">
|
|
<p><strong>Warning:</strong> This is a callout.</p>
|
|
</div>
|
|
```
|
|
|
|
**Skeleton** — `<div class="skeleton">` for loading placeholders.
|
|
|
|
**Spinner** — `<span class="spinner" role="status"><span class="visually-hidden">Loading...</span></span>`.
|
|
|
|
**Tables** — classless `<table>`. Kelp styles all tables automatically.
|
|
|
|
**Media** — classless `<img>`, `<video>`, `<audio>`. Responsive by default.
|
|
|
|
### Navigation
|
|
|
|
**Navbar** — `<nav class="navbar">`. Use with `.split` for layout.
|
|
|
|
```html
|
|
<header>
|
|
<nav class="navbar split">
|
|
<a href="/">Logo</a>
|
|
<div class="cluster">
|
|
<a href="/about">About</a>
|
|
<a href="/contact">Contact</a>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
```
|
|
|
|
**Subnav** — `<kelp-subnav>` web component. Horizontally scrollable navigation with overflow handling.
|
|
|
|
**Collapse Menu** — responsive nav that collapses into a toggle button on small screens.
|
|
|
|
**Tabs** — `<kelp-tabs>` web component. Progressive enhancement — without JS, content is a list of linked sections.
|
|
|
|
```html
|
|
<kelp-tabs>
|
|
<ul>
|
|
<li><a href="#tab1">Tab 1</a></li>
|
|
<li><a href="#tab2">Tab 2</a></li>
|
|
</ul>
|
|
<div id="tab1">Tab 1 content</div>
|
|
<div id="tab2">Tab 2 content</div>
|
|
</kelp-tabs>
|
|
```
|
|
|
|
### Forms
|
|
|
|
All form elements are **classless** — `<input>`, `<textarea>`, `<select>`, `<label>`, `<fieldset>`, `<legend>` are styled automatically.
|
|
|
|
```html
|
|
<!-- Good: no classes needed -->
|
|
<label for="email">Email</label>
|
|
<input type="email" id="email" name="email">
|
|
|
|
<!-- Good: utility class to nudge -->
|
|
<button class="primary">Submit</button>
|
|
```
|
|
|
|
**Checkbox** — classless `<input type="checkbox">`.
|
|
|
|
**Radio** — classless `<input type="radio">`.
|
|
|
|
**Switch** — `<input type="checkbox" role="switch">`.
|
|
|
|
**Password** — `<kelp-toggle-pw>` wraps password field to add show/hide toggle.
|
|
|
|
```html
|
|
<kelp-toggle-pw>
|
|
<label for="pw">Password</label>
|
|
<input type="password" id="pw" name="pw">
|
|
</kelp-toggle-pw>
|
|
```
|
|
|
|
**Color Picker** — classless `<input type="color">`.
|
|
|
|
**Date/Time Picker** — classless `<input type="date">`, `<input type="time">`, `<input type="datetime-local">`.
|
|
|
|
**File Picker** — classless `<input type="file">`.
|
|
|
|
**Select All** — `<kelp-select-all>` wrapping a group of checkboxes.
|
|
|
|
**Form Validation** — `<kelp-form-validate>` wraps a `<form>` for enhanced client-side validation with custom messages.
|
|
|
|
### Dialog / Overlay
|
|
|
|
All overlays use the native `<dialog>` element. **Never build custom overlay components.**
|
|
|
|
**Modal** — `<dialog>` with no extra class. Centered in viewport.
|
|
|
|
```html
|
|
<button commandfor="my-modal" command="show-modal">Open</button>
|
|
<dialog id="my-modal">
|
|
<p>Modal content</p>
|
|
<button commandfor="my-modal" command="close">Close</button>
|
|
</dialog>
|
|
```
|
|
|
|
**Drawer** — `<dialog class="drawer">`. Edge-aligned panel.
|
|
|
|
```html
|
|
<button commandfor="my-drawer" command="show-modal">Open</button>
|
|
<dialog class="drawer" id="my-drawer">
|
|
<p>Drawer content</p>
|
|
<button commandfor="my-drawer" command="close">Close</button>
|
|
</dialog>
|
|
```
|
|
|
|
Drawer positions: `.drawer` (end/right), `.drawer-start` (start/left), `.drawer-top`, `.drawer-bottom`.
|
|
|
|
**Dialog attributes:**
|
|
- `closedby="any"` — click backdrop to close (light dismiss)
|
|
- `closedby="none"` — prevent all dismissal except explicit `.close()`
|
|
- `autofocus` on an inner element — set initial focus
|
|
|
|
**Dialog sizing:** `.dialog-xs`, `.dialog-s`, `.dialog-l`, `.dialog-xl`, `.dialog-full`.
|
|
|
|
**Sticky header/footer:** Use `.action-header`, `.action-body`, `.action-footer` inside dialog for scrollable body with sticky header/footer.
|
|
|
|
**Events:** `cancel`, `close`, `command` — note: these do not bubble. Use `{capture: true}` if listening on a parent.
|
|
|
|
Kelp includes a polyfill for the `[command]`/`[commandfor]` attributes.
|
|
|
|
### Choosing Between Similar Components
|
|
|
|
**Expandable content:**
|
|
|
|
| Need | Component | JS Required |
|
|
|------|-----------|-------------|
|
|
| Static FAQ, accordion, inline expand/collapse | `<details>` + `<summary>` | No |
|
|
| Button-triggered show/hide with ARIA + events | `<kelp-disclosure>` | Yes |
|
|
| Dropdown menu | `<kelp-disclosure is-dropdown>` | Yes |
|
|
|
|
`<details>` uses native HTML, pushes content inline. `<kelp-disclosure>` adds full ARIA pattern, cancelable events, and can target any element by ID. Dropdown is just a disclosure with `[is-dropdown]` — auto-closes on outside click or Escape.
|
|
|
|
**Accordion:** Use multiple `<details>` elements with the same `[name]` attribute — the browser enforces only one open at a time.
|
|
|
|
```html
|
|
<details name="faq">
|
|
<summary>Question 1</summary>
|
|
<p>Answer 1</p>
|
|
</details>
|
|
<details name="faq">
|
|
<summary>Question 2</summary>
|
|
<p>Answer 2</p>
|
|
</details>
|
|
```
|
|
|
|
**Overlays:**
|
|
|
|
| Need | Pattern | Class |
|
|
|------|---------|-------|
|
|
| Centered dialog/modal | `<dialog>` | (none) |
|
|
| Side panel / drawer | `<dialog>` | `.drawer` |
|
|
| All overlays | `<dialog>` | Native element — never custom |
|
|
|
|
**Ajax:**
|
|
|
|
| Need | Component |
|
|
|------|-----------|
|
|
| Submit form without page reload | `<kelp-form-ajax>` wrapping `<form>` |
|
|
| Update page content after an event | `<kelp-html-ajax>` |
|
|
|
|
These pair together: form-ajax submits and emits events, html-ajax listens and updates content.
|
|
|
|
### Details Disclosure
|
|
|
|
Native HTML expand/collapse. No JavaScript required.
|
|
|
|
```html
|
|
<details>
|
|
<summary>Click to expand</summary>
|
|
<p>Hidden content here.</p>
|
|
</details>
|
|
```
|
|
|
|
Attributes: `[open]` (expanded by default), `[name]` (exclusive accordion groups).
|
|
|
|
### Disclosure (Web Component)
|
|
|
|
`<kelp-disclosure>` — button-triggered show/hide with ARIA.
|
|
|
|
```html
|
|
<kelp-disclosure target="#content">
|
|
<button>Toggle</button>
|
|
</kelp-disclosure>
|
|
<div id="content">Content to show/hide</div>
|
|
```
|
|
|
|
Attributes: `[target]` (ID selector), `[is-dropdown]`, `[hide-until-ready]`, `[show-until-ready]`.
|
|
|
|
Events: `kelp-disclosure:ready`, `kelp-disclosure:show-before` (cancelable), `kelp-disclosure:show`, `kelp-disclosure:hide-before` (cancelable), `kelp-disclosure:hide`.
|
|
|
|
Methods: `.show()`, `.hide()`, `.toggle()`, `.init()`.
|
|
|
|
### Dropdown
|
|
|
|
Alias of Disclosure with `[is-dropdown]`. Menu must be a `<ul>` nested inside.
|
|
|
|
```html
|
|
<kelp-disclosure is-dropdown>
|
|
<button>Menu</button>
|
|
<ul>
|
|
<li><a href="#">Link</a></li>
|
|
<li><button>Action</button></li>
|
|
</ul>
|
|
</kelp-disclosure>
|
|
```
|
|
|
|
Modifier: `.dropdown-end` on `<ul>` for right-aligned menu.
|
|
|
|
### Ajax Components
|
|
|
|
**Form Ajax** — wraps a `<form>` for async submission:
|
|
|
|
```html
|
|
<kelp-form-ajax msg-submitting="Sending..." msg-success="Done!" msg-failed="Error">
|
|
<form action="/api/submit" method="POST">
|
|
<label for="name">Name</label>
|
|
<input type="text" id="name" name="name">
|
|
<button>Submit</button>
|
|
</form>
|
|
</kelp-form-ajax>
|
|
```
|
|
|
|
Key attributes: `[msg-submitting]`, `[msg-success]`, `[msg-failed]`, `[redirect-on-success]`, `[path-on-success]`, `[path-on-failed]`, `[submit-loading]`, `[keep-fields]`, `[remove-form-on-success]`, `[dismiss-msg-on-success]`, `[delay]`, `[external-forms]`, `[event-keys]`, `[msg-start]`.
|
|
|
|
Events: `kelp-form-ajax:ready`, `kelp-form-ajax:submit` (cancelable), `kelp-form-ajax:success`, `kelp-form-ajax:failed`.
|
|
|
|
Progressive enhancement: the form still submits normally without JS.
|
|
|
|
**HTML Ajax** — listens for events and replaces its own content:
|
|
|
|
```html
|
|
<kelp-html-ajax id="item-list" events="kelp-form-ajax:success">
|
|
<ul>
|
|
<li>Item 1</li>
|
|
<li>Item 2</li>
|
|
</ul>
|
|
</kelp-html-ajax>
|
|
```
|
|
|
|
Attributes: `[events]` (comma-separated event names), `[keys]` (filter by event keys).
|
|
|
|
Events: `kelp-html-ajax:ready`, `kelp-html-ajax:before-replace` (cancelable), `kelp-html-ajax:replace`, `kelp-html-ajax:remove`, `kelp-html-ajax:failed`.
|
|
|
|
### Other Web Components
|
|
|
|
**`kelp-tabs`** — tabbed interface. Content is linked sections, progressively enhanced into tabs.
|
|
|
|
**`kelp-toc`** — auto-generated table of contents from headings.
|
|
|
|
**`kelp-autoexpand`** — wraps `<textarea>` to auto-grow with content.
|
|
|
|
**`kelp-toggle-pw`** — wraps password input to add show/hide toggle.
|
|
|
|
**`kelp-heading-anchors`** — adds anchor links to headings.
|
|
|
|
**`kelp-subnav`** — horizontally scrollable navigation.
|
|
|
|
**`kelp-form-validate`** — enhanced client-side form validation.
|
|
|
|
All web components follow the `kelp-*:event` naming convention for events. All support progressive enhancement — content is usable before JS loads.
|
|
|
|
---
|
|
|
|
## Utility Classes Reference
|
|
|
|
17 categories. Size modifiers follow the same scale as CSS variables (`-6xs` through `-6xl`).
|
|
|
|
| Category | Classes | Purpose |
|
|
|----------|---------|---------|
|
|
| Align Items | `.align-start`, `.align-center`, `.align-end` | Flex cross-axis alignment |
|
|
| Aspect Ratio | `.aspect-ratio-*` | Fixed aspect ratios |
|
|
| Color & Style | `.primary`, `.secondary`, `.success`, `.danger`, `.warning`, `.muted`, `.subtle`, `.filled` | Component color and fill |
|
|
| Display | `.block`, `.inline`, `.inline-block`, `.flex`, `.inline-flex`, `.grid`, `.none` | Display mode |
|
|
| Divided | `.divided` | Visual dividers between children |
|
|
| Fill | `.fill`, `.fill-*` | Background fills |
|
|
| Flexbox | `.flex-wrap`, `.flex-nowrap`, `.flex-grow`, `.flex-shrink`, `.direction-column`, `.direction-row` | Flex behavior |
|
|
| Gap | `.gap-*` | Space between flex/grid children |
|
|
| Hide Above | `.hide-above-*` | Hide above breakpoint |
|
|
| Justify Content | `.justify-start`, `.justify-center`, `.justify-end`, `.justify-between`, `.justify-around` | Flex main-axis alignment |
|
|
| Margin | `.margin-*`, `.margin-top-*`, `.margin-bottom-*`, etc. | Spacing outside |
|
|
| Motion | `.motion-reduced` | Disable animations |
|
|
| Padding | `.padding-*`, `.padding-top-*`, `.padding-bottom-*`, etc. | Spacing inside |
|
|
| Show Above | `.show-above-*` | Show above breakpoint |
|
|
| Size | `.size-*` | Font size (scales entire element via em) |
|
|
| Text | `.text-center`, `.text-left`, `.text-right`, `.text-uppercase`, `.text-lowercase`, `.text-capitalize`, `.text-truncate`, `.text-nowrap` | Text formatting |
|
|
| Visibility | `.visually-hidden`, `.visible` | Accessibility visibility |
|
|
|
|
---
|
|
|
|
## Output Format
|
|
|
|
### When generating UI code
|
|
|
|
- Show complete, copy-pasteable HTML — not fragments that require assembly
|
|
- Include CSS/JS link tags at the top if the component requires specific Kelp files
|
|
- Annotate with comments explaining which Kelp pattern is used:
|
|
|
|
```html
|
|
<!-- kelp: split layout -->
|
|
<div class="split">
|
|
<div>Left</div>
|
|
<div>Right</div>
|
|
</div>
|
|
```
|
|
|
|
- For web components, show the **progressive enhancement baseline first** (what works without JS), then the enhanced version:
|
|
|
|
```html
|
|
<!-- Without JS: linked sections -->
|
|
<ul>
|
|
<li><a href="#tab1">Tab 1</a></li>
|
|
<li><a href="#tab2">Tab 2</a></li>
|
|
</ul>
|
|
<div id="tab1">Tab 1 content</div>
|
|
<div id="tab2">Tab 2 content</div>
|
|
|
|
<!-- With kelp-tabs: enhanced into tabbed interface -->
|
|
<kelp-tabs>
|
|
<ul>
|
|
<li><a href="#tab1">Tab 1</a></li>
|
|
<li><a href="#tab2">Tab 2</a></li>
|
|
</ul>
|
|
<div id="tab1">Tab 1 content</div>
|
|
<div id="tab2">Tab 2 content</div>
|
|
</kelp-tabs>
|
|
```
|
|
|
|
### When reviewing existing code
|
|
|
|
Use the same finding format as the `developer` skill:
|
|
|
|
**[F1] [Short title]** -- [Critical/Major/Minor/Suggestion]
|
|
- **Location:** `file_path:line_number`
|
|
- **Issue:** [Description]
|
|
- **Recommended change:** [Describe what to change — show wrong vs right HTML]
|
|
|
|
Specifically flag anti-pattern violations with highest severity.
|
|
|
|
---
|
|
|
|
## Anti-Patterns
|
|
|
|
**These are critical violations.** Flag them immediately when reviewing code.
|
|
|
|
### 1. NEVER use Shadow DOM
|
|
|
|
```html
|
|
<!-- WRONG -->
|
|
<my-component>
|
|
#shadow-root
|
|
<style>...</style>
|
|
<slot></slot>
|
|
</my-component>
|
|
|
|
<!-- RIGHT: Light DOM web component -->
|
|
<kelp-tabs>
|
|
<ul>...</ul>
|
|
<div>...</div>
|
|
</kelp-tabs>
|
|
```
|
|
|
|
### 2. NEVER use JSX or framework components
|
|
|
|
```jsx
|
|
// WRONG
|
|
<Button variant="primary" onClick={handleClick}>Submit</Button>
|
|
|
|
// WRONG
|
|
function Card({ title, children }) { return <div className="card">...</div> }
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT: Plain HTML -->
|
|
<button class="primary">Submit</button>
|
|
```
|
|
|
|
### 3. NEVER assume a build step
|
|
|
|
```javascript
|
|
// WRONG
|
|
import styles from './component.module.css'
|
|
import { Button } from '@kelp/components'
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT: Link tags -->
|
|
<link rel="stylesheet" href="./css/kelp.css">
|
|
```
|
|
|
|
### 4. NEVER use Tailwind-style utility-first
|
|
|
|
```html
|
|
<!-- WRONG: utility-first -->
|
|
<h1 class="text-3xl font-bold text-gray-900 mb-4">Title</h1>
|
|
|
|
<!-- RIGHT: classless HTML (Kelp styles it) -->
|
|
<h1>Title</h1>
|
|
```
|
|
|
|
### 5. NEVER use className
|
|
|
|
```jsx
|
|
// WRONG (this is JSX, not HTML)
|
|
<button className="primary">Submit</button>
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT -->
|
|
<button class="primary">Submit</button>
|
|
```
|
|
|
|
### 6. NEVER write custom JS when a kelp-* web component exists
|
|
|
|
```javascript
|
|
// WRONG: custom tab implementation
|
|
document.querySelectorAll('.tab-button').forEach(btn => {
|
|
btn.addEventListener('click', () => { /* show/hide panels */ });
|
|
});
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT: use kelp-tabs -->
|
|
<kelp-tabs>
|
|
<ul>
|
|
<li><a href="#tab1">Tab 1</a></li>
|
|
</ul>
|
|
<div id="tab1">Content</div>
|
|
</kelp-tabs>
|
|
```
|
|
|
|
### 7. NEVER use @import for CSS
|
|
|
|
```css
|
|
/* WRONG */
|
|
@import url('./kelp.css');
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT -->
|
|
<link rel="stylesheet" href="./kelp.css">
|
|
```
|
|
|
|
### 8. NEVER use div-soup when semantic HTML works
|
|
|
|
```html
|
|
<!-- WRONG -->
|
|
<div class="nav">
|
|
<div class="nav-item" onclick="navigate()">Home</div>
|
|
</div>
|
|
|
|
<!-- RIGHT -->
|
|
<nav>
|
|
<a href="/">Home</a>
|
|
</nav>
|
|
```
|
|
|
|
### 9. NEVER add classes to classless elements
|
|
|
|
```html
|
|
<!-- WRONG -->
|
|
<h1 class="heading">Title</h1>
|
|
<input class="input" type="text">
|
|
<p class="paragraph">Text</p>
|
|
|
|
<!-- RIGHT: Kelp styles these automatically -->
|
|
<h1>Title</h1>
|
|
<input type="text">
|
|
<p>Text</p>
|
|
```
|
|
|
|
### 10. NEVER use @apply or CSS-in-JS
|
|
|
|
```css
|
|
/* WRONG */
|
|
.my-button { @apply bg-blue-500 text-white px-4 py-2; }
|
|
```
|
|
|
|
```javascript
|
|
// WRONG
|
|
const styles = css`background: blue; color: white;`
|
|
```
|
|
|
|
```css
|
|
/* RIGHT: Use Kelp cascade layers and CSS variables */
|
|
@layer kelp.extend {
|
|
.my-button {
|
|
--background-color: var(--color-blue-50);
|
|
--color: white;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 11. NEVER wrap Kelp web components in framework lifecycle
|
|
|
|
```javascript
|
|
// WRONG: React lifecycle managing Kelp component
|
|
useEffect(() => {
|
|
const tabs = document.querySelector('kelp-tabs');
|
|
tabs.init();
|
|
return () => tabs.destroy();
|
|
}, []);
|
|
```
|
|
|
|
```html
|
|
<!-- RIGHT: Kelp components self-initialize via progressive enhancement -->
|
|
<kelp-tabs>
|
|
<ul>...</ul>
|
|
<div>...</div>
|
|
</kelp-tabs>
|
|
<!-- Just include kelp.js — components handle their own lifecycle -->
|
|
```
|
|
|
|
---
|
|
|
|
## Iteration
|
|
|
|
When Sam provides feedback on generated HTML:
|
|
- Update only the affected section — do not regenerate the entire page
|
|
- Show the complete component after the edit (not fragments)
|
|
- Annotate changes with comments: `<!-- UPDATED: [what changed] -->`
|
|
- Flag if a requested change would break progressive enhancement or violate a core principle
|
|
|
|
## Complexity Scaling
|
|
|
|
**Simple tasks** (single component, one layout, quick review):
|
|
- Show the HTML directly without preamble
|
|
- Flag: "Simplified output — request full page structure if needed"
|
|
|
|
**Complex tasks** (full page, multiple interacting components):
|
|
- Show the layout skeleton first (container, major sections)
|
|
- Then detail each section's components
|
|
- Include all necessary link tags and scripts
|
|
|
|
## Initiative Integration
|
|
|
|
When Sam links this to an initiative:
|
|
- Read the initiative's PID, PRD, or overview document for context
|
|
- Align component selection with the initiative's UI requirements
|
|
- Reference the project's AGENTS.md for any Kelp-specific conventions (custom theme, layout patterns)
|
|
- The output stays in the conversation for refinement — Sam will decide when to apply changes
|
|
|
|
## Related Skills
|
|
|
|
- **`developer`** — suggest loading for architecture decisions, code review beyond Kelp-specific patterns, or backend implementation
|
|
- **`ui-design`** — suggest loading for design token definitions that map to Kelp CSS variables
|
|
- **`ux-design`** — suggest loading for user flow design that informs component selection
|
|
- **`seo`** — suggest loading for semantic HTML optimization and structured data (Kelp's semantic approach directly benefits SEO)
|
|
- **`qa`** — suggest loading for test cases covering component states and progressive enhancement behavior
|
|
|
|
## Constraints
|
|
|
|
- Advisory only: describe changes and show HTML. Do not apply changes without Sam's explicit approval.
|
|
- Source of truth is `kelpui.com/docs` — not any local repository.
|
|
- When uncertain about any feature, use WebFetch to check the current docs before recommending.
|
|
- Prefer semantic HTML over ARIA workarounds — use native elements first.
|
|
- Always verify progressive enhancement: content must be usable without JavaScript.
|
|
- If unsure about any aspect, state the uncertainty and ask Sam before proceeding.
|