components skill
The components skill drives /kit-add and /kit-create. It defines the seven-step generation workflow, the component reference system, and all the conventions that keep generated code consistent across every component.
Trigger
Section titled “Trigger”The components skill is triggered by /kit-add and /kit-create. It provides both the standard generation workflow (Steps 0, A–F) and the Creator Mode and Form Mode sections that were previously handled by the separate component-creator and component-form pilot skills (absorbed in v1.0.0).
The seven steps (0, A–F)
Section titled “The seven steps (0, A–F)”-
Step 0 — Exit plan mode. If the session is in plan mode, exit it before any other work. Step B reads
package.jsonand copiesui.tsx, and Step D writes the generated component files — plan mode would block both. The skill only stays in plan mode when the user asked for a description without running anything. -
Step A — Resolve component name. The skill looks up the requested name in the component reference catalogue (
skills/components/references/catalog.md). Names are normalized (case-insensitive, hyphenated or camelCase both accepted). If a name doesn’t match, the skill lists the closest alternatives and stops. -
Step B — Verify sass and copy
ui.tsxandfoundation.css. ChecksdevDependenciesinpackage.jsonforsass. If missing, halts with an install command. Then applies the three-case foundation install matrix (see Foundation CSS install below). -
Step C — Resolve dependency tree. Reads the component’s spec doc for its
dependencies:list, then recursively resolves each dependency’s dependencies. The result is a flat, deduplicated list ordered from leaf to root (bottom-up). -
Step D — Generate bottom-up. Starting from leaf components, each is generated in turn. The skill reads the component’s reference spec, builds the TSX file in memory using the generation contract, then writes it. Components that already exist in the target directory are skipped.
-
Step E — Handle existing files. When a file already exists, its import path is captured and used in parent components instead of re-generating it. The summary marks these as “skipped — existing file imported.”
-
Step F — Display summary. After all files are written, the skill prints a summary table and the import statement(s) to add to your code.
Foundation CSS install
Section titled “Foundation CSS install”On Step B, the skill applies a three-case matrix to determine whether to copy foundation.css and the foundation/sass/ source tree alongside ui.tsx:
| Project state | Action |
|---|---|
Neither ui.tsx nor foundation.css present (fresh install) | Copy ui.tsx, foundation.css, and the full foundation/sass/ tree; print an import hint |
ui.tsx present, foundation.css absent (existing install) | Prompt the developer before copying — explains the CSS reset, @layer ordering, and spacing/shadow tokens; the developer can opt out |
Both ui.tsx and foundation.css present | Skip silently (idempotent) |
foundation.css declares the canonical @layer cascade order for consumer projects:
@layer foundation, components, utilities, theme;The cascade outcome — theme > utilities > components > foundation — means theme tokens always win. Import foundation.css once in your project entrypoint before any component SCSS.
The generation contract
Section titled “The generation contract”Every component spec doc includes a generation contract — a declaration of exactly what files will be produced:
Generation contract: Button.tsx src/components/fpkit/Button.tsx Button.scss src/components/fpkit/Button.scss
Imports: import { UI } from './ui'; import './Button.scss';
TypeScript interface: ButtonProps { children, variant?, size?, disabled?, onClick?, className? }The skill uses this contract to verify output before writing. If the generated file doesn’t match the contract (wrong exports, missing types, wrong import paths), it retries once with corrections.
Component reference docs
Section titled “Component reference docs”Each component has a spec doc in skills/components/references/components/<name>.md. The spec includes:
- Category — simple / interactive / form / layout / complex
- Generation contract — exact file names and import paths
- Props — TypeScript interface with types, required/optional, defaults
- CSS tokens — every
--comp-*variable with its role and fallback - Accessibility — ARIA roles, keyboard behavior, focus management
- Dependencies — other components required
- Usage examples — copy-paste JSX snippets
CSS variable naming convention
Section titled “CSS variable naming convention”All component tokens follow the --comp-role-descriptor pattern:
| Segment | Meaning | Example |
|---|---|---|
comp | Component abbreviation | btn, card, dlg |
role | Semantic role | bg, color, border, radius |
descriptor | Optional modifier | hover, focus, active, disabled |
Approved abbreviations:
bg→ backgroundbd/border→ borderrad/radius→ border-radiusclr/color→ text colorsz/size→ font-sizefw→ font-weightpx,py→ horizontal/vertical paddingmx,my→ horizontal/vertical marginel→ elevation / shadow
Inline type pattern
Section titled “Inline type pattern”Generated TypeScript interfaces are always inline in the component file — never imported from a shared types file:
// ✓ Inline types — what the skill generatesexport interface ButtonProps { children: React.ReactNode; variant?: "primary" | "secondary" | "ghost" | "danger";}
// ✗ Imported types — the skill never does thisimport type { ButtonProps } from "../types/button";This keeps each component self-contained and makes it easy to copy a single file into any project.
The UI polymorphic base
Section titled “The UI polymorphic base”Every component uses the UI base component from ui.tsx:
export function Button({ children, ...props }: ButtonProps) { return ( <UI as="button" {...props}> {children} </UI> );}UI accepts an as prop and forwards all HTML attributes to the correct element. It also handles the data-* attribute pattern used for variants and states.
aria-disabled pattern
Section titled “aria-disabled pattern”The skill uses aria-disabled="true" instead of the disabled attribute for interactive components. This preserves keyboard focusability and screen reader announcement while visually appearing disabled:
<UI as="button" aria-disabled={disabled} onClick={disabled ? undefined : onClick}>The disabled visual state is styled via the CSS selector [aria-disabled="true"] in the component’s SCSS.
Extending a generated component
Section titled “Extending a generated component”Generated components are meant to be edited. After running /kit-add, you own the files. Common extension patterns:
Add a new variant — add a data-variant value and its CSS:
&[data-variant="outline"] { --btn-bg: transparent; --btn-border: var(--color-primary);}Add a prop — extend the TypeScript interface and add the conditional attribute:
interface ButtonProps { loading?: boolean;}// In render:aria-busy={loading}Override a token — in your app CSS, not in the generated file:
.btn { --btn-radius: 9999px;}