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

29 KiB


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 HTML > Utility > Group 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
<!-- 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.

<!-- 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.

<!-- 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

<!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:

@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.

<!-- 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>:

<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.

<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.

<!-- 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.

<div class="cluster">
  <span>Tag 1</span>
  <span>Tag 2</span>
  <span>Tag 3</span>
</div>

Split

Push items to opposite edges.

<!-- 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.

<!-- 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.

<div class="stack">
  <h2>Section Title</h2>
  <p>Content paragraph.</p>
  <button>Action</button>
</div>

Text

Sets optimal line length for readable text.

<div class="text">
  <p>Long paragraph of readable content...</p>
</div>

Action Header

Title + actions in a row, with title taking priority.

<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.

<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.

<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.

<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.

<!-- 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.

<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.

<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.

<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.

<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.

<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.

<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.

<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:

<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:

<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:
<!-- 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:
<!-- 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

<!-- 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

// WRONG
<Button variant="primary" onClick={handleClick}>Submit</Button>

// WRONG
function Card({ title, children }) { return <div className="card">...</div> }
<!-- RIGHT: Plain HTML -->
<button class="primary">Submit</button>

3. NEVER assume a build step

// WRONG
import styles from './component.module.css'
import { Button } from '@kelp/components'
<!-- RIGHT: Link tags -->
<link rel="stylesheet" href="./css/kelp.css">

4. NEVER use Tailwind-style utility-first

<!-- 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

// WRONG (this is JSX, not HTML)
<button className="primary">Submit</button>
<!-- RIGHT -->
<button class="primary">Submit</button>

6. NEVER write custom JS when a kelp-* web component exists

// WRONG: custom tab implementation
document.querySelectorAll('.tab-button').forEach(btn => {
  btn.addEventListener('click', () => { /* show/hide panels */ });
});
<!-- 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

/* WRONG */
@import url('./kelp.css');
<!-- RIGHT -->
<link rel="stylesheet" href="./kelp.css">

8. NEVER use div-soup when semantic HTML works

<!-- 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

<!-- 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

/* WRONG */
.my-button { @apply bg-blue-500 text-white px-4 py-2; }
// WRONG
const styles = css`background: blue; color: white;`
/* 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

// WRONG: React lifecycle managing Kelp component
useEffect(() => {
  const tabs = document.querySelector('kelp-tabs');
  tabs.init();
  return () => tabs.destroy();
}, []);
<!-- 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
  • 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.