@spark-web/design-system
Version:
--- title: Design System ---
272 lines (193 loc) • 9.11 kB
Markdown
# Layer 3 — Component CLAUDE.md files
## What this layer is
Every component package that an agent is expected to use gets its own
`CLAUDE.md` inside `packages/[component]/`. This file is the agent's contract
for that component: what it does, how its pieces fit together, what tokens to
use, and what it must never do.
This is the most granular layer. It is read last — only after the surface
classifier, surface rules, and feature pattern have already been read. By the
time the agent reaches this file it already knows _which_ components to use and
_why_. This file tells it _how_.
## Where these files live
```
packages/
table/
CLAUDE.md ← component rules for @spark-web/table
src/
Table.tsx
table.stories.tsx
table.test.tsx
status-badge/
CLAUDE.md
meatball/
CLAUDE.md
header/
CLAUDE.md
...
```
One `CLAUDE.md` per package. Not one per sub-component — one per package.
## Anatomy of a component CLAUDE.md
The sections below are the standard structure. Every component file should
follow this shape. Use `@spark-web/table` as the reference example.
### Section 1 — What this package is
One short paragraph. Plain language. States the component's purpose and its
compositional structure (sub-components, if any).
```markdown
## What this package is
A composable table component for displaying tabular data. Five sub-components
used together: Table, TableHeaderRow, TableHeaderCell, TableRow, TableCell.
Optional TablePagination is a separate compositional layer used OUTSIDE Table.
```
### Section 2 — What this package is NOT
Equally important. Explicitly rules out common misuses. This prevents the agent
from reaching for this component when a different one is needed, and prevents it
from adding features the component was never designed to have.
```markdown
## What this package is NOT
- Not a data-grid. No virtual scrolling, column reordering, or column resizing.
- Not a standalone component. TableRow and TableCell are meaningless outside
Table.
- Not responsible for data fetching, sorting, or filtering.
```
### Section 3 — Component hierarchy
Shows the parent/child relationship between sub-components. For simple single-
component packages this can be omitted. For composable packages it is essential.
```markdown
## Component hierarchy
Table ← scroll container, layout owner TableHeaderRow ← always first child of
Table TableHeaderCell ← one per column, owns sort state TableRow (× n) ← one per
data row, owns row state TableCell (× n) ← one per column per row
TableRow[state=loading] ← replaces data rows during fetch, no children
TablePagination is always OUTSIDE and BELOW Table — never inside it.
```
### Section 4 — Token usage
All design token values the component uses, grouped by category. This is the
most mechanical section and must be exhaustive — if a token is omitted the agent
will either guess or use a raw value.
Every token must reference `useTheme()` from `@spark-web/theme`. Raw hex values,
pixel values, and Tailwind classes are never acceptable.
```markdown
## Token usage
All values from useTheme() from @spark-web/theme.
### Spacing tokens
Cell padding all sides: theme.spacing.large Header cell padding horizontal:
theme.spacing.large Pagination gap between buttons: theme.spacing.small
### Color tokens
Cell background default: theme.color.background.surface Cell background hover:
theme.color.background.inputPressed Cell text default:
theme.color.foreground.neutral Header cell background:
theme.color.background.surface
### Typography
Use @spark-web/text for all text. Never raw <p> or <span>. Cell content:
<Text tone="neutral"> using Body/Small scale Header cell label:
<Text weight="semibold"> using xSmall scale
```
### Section 5 — States (if applicable)
For components with visual states, list every valid state, the prop that
controls it, and the tokens that apply. Be specific about which states interact
(e.g. hover must not apply when state is disabled).
```markdown
## Row states
state prop on TableRow: 'default' | 'selected' | 'disabled' | 'loading' Hover is
CSS :hover only — not a state prop.
default: theme.color.background.surface, text theme.color.foreground.neutral
hover: theme.color.background.inputPressed, text theme.color.foreground.neutral
selected: theme.color.background.primarySoft, text
theme.color.foreground.neutral disabled: theme.color.background.inputDisabled,
text theme.color.foreground.disabled, pointer-events none loading:
theme.color.background.surface, renders "Loading" + spinner, ignores children
Hover must NOT apply when state is disabled or loading.
```
### Section 6 — Composition rules
Numbered constraints on how sub-components must be assembled. These prevent
structural errors that would silently render incorrectly or break at runtime.
```markdown
## Composition rules
1. Table must always contain exactly one TableHeaderRow as its first child.
2. TableHeaderRow must contain one TableHeaderCell per column.
3. TableRow must contain the same number of TableCell children as header
columns.
4. A loading TableRow ignores all children.
5. TablePagination is always a sibling of Table, never a child.
```
### Section 7 — Do NOTs
A bulleted list of the most common agent mistakes for this component, stated as
explicit prohibitions. These should cover the things an agent would most likely
get wrong if it had only read the component source code without this file.
```markdown
## Do NOTs
- NEVER raw hex values e.g. #1a2a3a — always use theme color tokens
- NEVER raw pixel values e.g. 16px — always use theme spacing/sizing tokens
- NEVER Tailwind classes — use Emotion CSS-in-JS via useTheme()
- NEVER TableCell state prop — state on TableRow only
- NEVER TablePagination inside Table
- NEVER raw <table> <tr> <th> <td> HTML elements
- NEVER omit forwardRef
- NEVER re-implement the status dot/pill inline — use StatusBadge
```
## How this layer defers to surface rules
A component CLAUDE.md defines _default_ behaviour. Surface rules override those
defaults for a specific product context.
Example: the table component has a hover state. The component CLAUDE.md defines
the token to use for that hover state. The internal admin surface rules define
_when_ hover is applied at all (only on clickable rows). The component file does
not repeat the surface rule — it only documents what the hover state looks like
when it is applied.
If you find yourself writing a rule in a component CLAUDE.md that says "on admin
pages, do X" — stop. That rule belongs in the surface rules file, not here.
## When to create a component CLAUDE.md
Create one when any of the following are true:
- The component has sub-components that must be assembled in a specific order
- The component uses design tokens that an agent would otherwise guess at
- There are common misuses that would be hard to catch from the component's
TypeScript types alone
- The component has states or variants with non-obvious visual behaviour
- The component depends on another package that must always be used alongside it
Do NOT create one for simple, single-element components with no configuration
surface. If the TypeScript types and stories are sufficient, a CLAUDE.md adds no
value.
## Relationship to Storybook stories
The component CLAUDE.md defines rules. The `.stories.tsx` file shows correct
usage in real-world context. Both are required reading for the agent — the
CLAUDE.md alone may not cover every prop combination, and stories alone do not
explain why constraints exist.
The reading order from the root file enforces this:
```
4. packages/[component]/CLAUDE.md ← rules
5. packages/[component]/src/[component].stories.tsx ← usage examples
```
Never reference a story in the CLAUDE.md and say "see stories for examples" as a
substitute for writing out the composition rules. The rules must be explicit in
this file.
## What happens if this layer is missing or incomplete
- The agent uses raw values (`#1a2a3a`, `16px`) instead of theme tokens,
breaking dark mode support and responsive scaling.
- Sub-components are assembled in the wrong order or at the wrong nesting level
(e.g. `TablePagination` inside `Table`).
- State props are applied to the wrong sub-component.
- The agent re-implements functionality that already exists in a dependency
(e.g. builds a custom status pill instead of using `@spark-web/status-badge`).
## Installed component context
When `@spark-web/design-system` is installed, component-level CLAUDE.md files
are available at `node_modules/@spark-web/{name}/CLAUDE.md`. Read the relevant
file before working with any of the following components:
- `node_modules/@spark-web/description-list/CLAUDE.md`
- `node_modules/@spark-web/highlight-card/CLAUDE.md`
- `node_modules/@spark-web/overflow-menu/CLAUDE.md`
- `node_modules/@spark-web/section-card/CLAUDE.md`
- `node_modules/@spark-web/section-header/CLAUDE.md`
- `node_modules/@spark-web/tag/CLAUDE.md`