Files
opencode-skills/skills/kelp-ui/SKILL.md
T

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.