UI engineering
Build UIs that are composable, token-driven, and boring to maintain — not one-off styled divs.
Stack defaults (modern web)
| Concern |
Preferred |
When to diverge |
| Components |
React function components + TypeScript |
Existing Vue/Svelte repo — match repo |
| Primitives |
Radix UI / native semantic HTML |
No React — use platform primitives |
| Styling |
Tailwind CSS + CSS variables for tokens |
Existing CSS Modules — extend, don't rewrite |
| Component kit |
shadcn/ui (copy-in, you own code) |
MUI/Chakra legacy — migrate incrementally via shadcn |
| Icons |
lucide-react (direct imports, not barrel) |
Match repo icon set |
| Forms |
react-hook-form + Zod resolver |
Server Actions + progressive enhancement in Next |
Follow repo conventions when they differ; do not rip working UI for stack purity.
Design tokens (do this before pixel-pushing)
Define once, reference everywhere:
/* semantic tokens — not raw hex in components */
--background, --foreground, --primary, --muted, --border, --radius
- Spacing scale: 4px base (Tailwind default)
- Type scale: 2–3 body sizes + 1–2 display; limit font families to 1–2
- Radius/shadow: 2 levels max for cohesion
Components consume tokens (bg-background, text-muted-foreground), not #1a1a1a.
Component structure
components/
ui/ ← shadcn primitives (Button, Input) — thin, unmodified when possible
features/ ← domain-specific (InvoiceTable, UserMenu)
layouts/ ← shells (AppShell, SettingsLayout)
Rules:
- ui/ has no business logic and no data fetching.
- features/ compose ui/ + hooks; one primary user task per folder.
- Props are explicit — prefer
{ invoice: Invoice } over spreading unknown bags.
Composition patterns
| Pattern |
Use |
| Compound components |
Tabs, accordion — shared context, flexible children |
Slot / asChild |
Radix — style triggers without wrapper div soup |
| Variants |
cva or tailwind-variants for Button size/intent — not 12 boolean props |
| Controlled vs uncontrolled |
Document which; default uncontrolled for simple inputs |
Responsive & layout
- Mobile-first Tailwind breakpoints (
sm:, md:).
- Prefer CSS Grid/Flex over absolute positioning for page layout.
- Touch targets ≥ 44×44px; do not rely on hover-only affordances.
Deliverable-first UI
Before JSX, list from deliverable-first:
- States: loading, empty, error, success
- Primary + secondary actions
- Data shape props require
Implement empty and error states first — they expose missing API contracts early.
Quality bar
Handoffs
| Need |
Skill |
| User flows, heuristics, a11y audit depth |
ux-engineering |
| shadcn add/update CLI |
shadcn |
| Next.js Server Components |
nextjs |
| Perf waterfalls / bundle |
react-best-practices |
1---2name: ui-engineering3description: Modern UI implementation: component composition, design tokens, Tailwind/shadcn/Radix stacks, responsive layout, and accessible markup foundations. Use when building or refactoring UI components, pages, design systems, or styling. Scope boundary: React/Next render performance → `react-best-practices`; shadcn CLI install and registries → `shadcn`; App Router data fetching and RSC → `nextjs`; UX flows and copy → `ux-engineering`.4---5# UI engineering67Build UIs that are **composable, token-driven, and boring to maintain** — not one-off styled divs.89## Stack defaults (modern web)1011| Concern | Preferred | When to diverge |12|---|---|---|13| Components | React function components + TypeScript | Existing Vue/Svelte repo — match repo |14| Primitives | Radix UI / native semantic HTML | No React — use platform primitives |15| Styling | Tailwind CSS + CSS variables for tokens | Existing CSS Modules — extend, don't rewrite |16| Component kit | shadcn/ui (copy-in, you own code) | MUI/Chakra legacy — migrate incrementally via `shadcn` |17| Icons | lucide-react (direct imports, not barrel) | Match repo icon set |18| Forms | react-hook-form + Zod resolver | Server Actions + progressive enhancement in Next |1920Follow repo conventions when they differ; do not rip working UI for stack purity.2122## Design tokens (do this before pixel-pushing)2324Define once, reference everywhere:2526```css27/* semantic tokens — not raw hex in components */28--background, --foreground, --primary, --muted, --border, --radius29```3031- **Spacing scale:** 4px base (Tailwind default)32- **Type scale:** 2–3 body sizes + 1–2 display; limit font families to 1–233- **Radius/shadow:** 2 levels max for cohesion3435Components consume tokens (`bg-background`, `text-muted-foreground`), not `#1a1a1a`.3637## Component structure3839```40components/41 ui/ ← shadcn primitives (Button, Input) — thin, unmodified when possible42 features/ ← domain-specific (InvoiceTable, UserMenu)43 layouts/ ← shells (AppShell, SettingsLayout)44```4546**Rules:**47- **ui/** has no business logic and no data fetching.48- **features/** compose ui/ + hooks; one primary user task per folder.49- Props are **explicit** — prefer `{ invoice: Invoice }` over spreading unknown bags.5051## Composition patterns5253| Pattern | Use |54|---|---|55| **Compound components** | Tabs, accordion — shared context, flexible children |56| **Slot / `asChild`** | Radix — style triggers without wrapper div soup |57| **Variants** | `cva` or `tailwind-variants` for Button size/intent — not 12 boolean props |58| **Controlled vs uncontrolled** | Document which; default uncontrolled for simple inputs |5960## Responsive & layout6162- Mobile-first Tailwind breakpoints (`sm:`, `md:`).63- Prefer **CSS Grid/Flex** over absolute positioning for page layout.64- Touch targets ≥ 44×44px; do not rely on hover-only affordances.6566## Deliverable-first UI6768Before JSX, list from `deliverable-first`:69701. States: loading, empty, error, success712. Primary + secondary actions723. Data shape props require7374Implement **empty and error states first** — they expose missing API contracts early.7576## Quality bar7778- [ ] Semantic HTML (`button` not `div onClick`, `nav`, `main`, headings in order)79- [ ] Focus visible on interactive elements80- [ ] No inline styles except dynamic values81- [ ] Story or test for non-trivial component states82- [ ] `real-time-testing`: component test or typecheck after edits8384## Handoffs8586| Need | Skill |87|---|---|88| User flows, heuristics, a11y audit depth | `ux-engineering` |89| shadcn add/update CLI | `shadcn` |90| Next.js Server Components | `nextjs` |91| Perf waterfalls / bundle | `react-best-practices` |