Repository navigation
Expand file tree
/
Copy pathreact-sot-ui-primitives.mdc
More file actions
69 lines (48 loc) · 2.9 KB
/
Copy pathreact-sot-ui-primitives.mdc
File metadata and controls
69 lines (48 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
---
description: Repeating UI chrome (buttons, headings, chips) — one SOT + variant Storybook stories before routes
globs: "web/src/components/ui/**/*.{tsx,css},web/.storybook/**/*.{ts,tsx}"
alwaysApply: false
---
# UI primitives — one SOT, variant stories (step 10g)
Webflow exports repeat the same **UI chrome** on every page: buttons, eyebrow chips, heading scales, icon slots. During migration, extract each pattern into **one** React component with **Storybook variant stories** — not per-route markup.
## Two-tier SOT model
| Tier | Examples | Storybook folder | When |
| --- | --- | --- | --- |
| **UI primitives (10g)** | Button, Tagline, Heading, CopyableCodeBlock | `Components/UI/…` | Before section SOT |
| **Page sections (11a)** | Hero, logo band, FAQ, CTA band | `Components/Page sections/…` | Before routes (11) |
Sections **compose** primitives. Section CSS must not reimplement button borders, chip colors, or heading scales.
## Audit signals (export)
| Pattern | Typical export classes |
| --- | --- |
| CTAs | `.button`, `.w-button`, `.is-secondary`, `.is-icon` |
| Eyebrows | mono uppercase bordered chips |
| Headings | `.heading-style-h1` … `h6`, or repeated title classes |
| Code snippets | toolbar + monospace + copy |
Grep CSS and HTML before porting routes. **One component per pattern.**
## Required pattern
```tsx
// Components/UI/Button.tsx — one SOT
<Button variant="primary" theme="dark" href="/signup">Try it free</Button>
// Components/UI/Button.stories.tsx — variants, not routes
export const Primary: Story = { args: { variant: 'primary', children: 'Try it free' } }
export const Secondary: Story = { args: { variant: 'secondary', children: 'Talk to us' } }
```
Routes and page sections import `Button` — never:
```tsx
// Forbidden on new work
<a href="…" className="button w-button is-secondary">…</a>
```
## CSS ownership
- Primitive chrome (colors, padding, borders, font) → component CSS or global design-system entry.
- **Forbidden:** route `*-page.css` targeting `.button`, `.w-button`, or `.ui-button__*` internals.
- **Forbidden:** different button markup per page when `Button` SOT exists.
## Storybook
- Install and wire **preview** in step **10f** before **10g**.
- Primitive stories use the **same stylesheet tier** as production.
- Name stories after **variants** (Primary, Secondary, On dark) — not after routes (Home CTA, Pricing CTA).
## Client-side upgrade anti-pattern
Do not ship export buttons and replace them after hydration (`createRoot`, `replaceWith`, mount-time class swapping). SSR and Storybook must show SOT markup on first paint.
## Related
- [checklists/ui-primitives-pass.md](../checklists/ui-primitives-pass.md) — step 10g gate
- [checklists/section-sot-pass.md](../checklists/section-sot-pass.md) — step 11a (sections compose primitives)
- [rules/react-sot-storybook-parity.mdc](react-sot-storybook-parity.mdc) — story = production contract