Frontend UI Engineering
Build components that are reusable, accessible, and performant. Don't make one big file with everything in it.
Progress Checklist
Step 0: Detect Framework
# Check what we're working with
cat package.json 2>/dev/null | grep -E "react|vue|svelte|angular|next|nuxt|astro"
ls src/components/ app/components/ components/ 2>/dev/null | head -10
Match the project's existing component patterns, naming conventions, and file organization.
Step 1: Component Hierarchy
Build at the right level of abstraction. Small, reusable pieces compose into larger ones:
- Tokens / Primitives: Colors, spacing, typography, icons. Design system foundation.
- Base Components: Buttons, inputs, cards, modals. Generic, no business logic.
- Composite Components: Forms, data tables, navigation. Combine base components.
- Features / Views: Full sections with business logic, data fetching, routing.
- Pages / Layouts: Top-level composition, page structure.
Rules:
- Each component does one thing
- If a component file is > 200 lines, it probably does too much
- Reuse existing components before creating new ones
- Don't create abstractions for things used only once
Step 2: Separate Concerns
Data fetching and presentation are different jobs:
- Container / Smart: Fetches data, manages state, handles events
- Presentation / Dumb: Receives props, renders UI, fires callbacks
This makes components testable (presentation) and keeps data logic centralized (container).
Framework-specific patterns:
- React: Custom hooks for data, components for rendering
- Vue: Composables for data, components for rendering
- Next.js/Nuxt: Server components for data, client components for interactivity
Step 3: Handle All States
Every component that deals with data needs these states:
| State |
What to show |
| Loading |
Skeleton, spinner, or placeholder. Not a blank screen. |
| Error |
Clear message, retry action if possible. Not a crash. |
| Empty |
Helpful message, maybe a CTA. Not "No results." with no context. |
| Success |
The actual content. |
| Partial |
Some data loaded, some still loading. Progressive rendering. |
Step 4: Accessibility
This is a requirement, not a feature. Client work may have legal requirements (WCAG 2.1 AA).
Non-negotiables:
- All interactive elements reachable by keyboard (Tab, Enter, Escape, Arrow keys)
- Semantic HTML elements (
button not div onClick, nav, main, article)
- Form inputs have associated labels
- Images have alt text (or
alt="" for decorative)
- Color contrast meets WCAG AA (4.5:1 for normal text, 3:1 for large text)
- Focus indicators visible
- Screen reader compatible (test with VoiceOver: Cmd+F5 on macOS)
For detailed patterns, see ../codebase-audit/references/accessibility-checklist.md.
Step 5: Performance
Be conscious of what you ship:
- Lazy load routes and heavy components (code splitting)
- Optimize images: correct size, modern format (WebP/AVIF), lazy loading
- Avoid unnecessary re-renders: memoize expensive computations, stable references for callbacks/objects in props
- Monitor bundle size: importing a whole library for one function is expensive
- Virtualize long lists: don't render 1000 DOM nodes when 20 are visible
Step 6: Verify
When a URL is available, trigger the chrome-devtools skill to verify:
- Console is clean (no errors, no warnings)
- Network requests are correct
- Visual output matches expectations (screenshot)
- Accessibility tree is correct
- Lighthouse scores are acceptable
- No layout shifts or jank
1---2name: frontend-ui-engineering3description: Guides frontend UI development with component hierarchy, separation of concerns, accessibility as requirement, and performance awareness. Framework-agnostic, detects stack from project. Triggers chrome-devtools for verification. Use when building UI, frontend development, creating components, UI engineering, component architecture, building pages, or when working on frontend code.4---56# Frontend UI Engineering78Build components that are reusable, accessible, and performant. Don't make one big file with everything in it.910## Progress Checklist1112- [ ] Detect framework and existing patterns13- [ ] Design component hierarchy14- [ ] Separate data fetching from presentation15- [ ] Handle all states (loading, error, empty)16- [ ] Ensure accessibility17- [ ] Check performance impact18- [ ] Verify with chrome-devtools (if URL available)1920## Step 0: Detect Framework2122```bash23# Check what we're working with24cat package.json 2>/dev/null | grep -E "react|vue|svelte|angular|next|nuxt|astro"25ls src/components/ app/components/ components/ 2>/dev/null | head -1026```2728Match the project's existing component patterns, naming conventions, and file organization.2930## Step 1: Component Hierarchy3132Build at the right level of abstraction. Small, reusable pieces compose into larger ones:3334- **Tokens / Primitives**: Colors, spacing, typography, icons. Design system foundation.35- **Base Components**: Buttons, inputs, cards, modals. Generic, no business logic.36- **Composite Components**: Forms, data tables, navigation. Combine base components.37- **Features / Views**: Full sections with business logic, data fetching, routing.38- **Pages / Layouts**: Top-level composition, page structure.3940Rules:41- Each component does one thing42- If a component file is > 200 lines, it probably does too much43- Reuse existing components before creating new ones44- Don't create abstractions for things used only once4546## Step 2: Separate Concerns4748Data fetching and presentation are different jobs:4950- **Container / Smart**: Fetches data, manages state, handles events51- **Presentation / Dumb**: Receives props, renders UI, fires callbacks5253This makes components testable (presentation) and keeps data logic centralized (container).5455Framework-specific patterns:56- React: Custom hooks for data, components for rendering57- Vue: Composables for data, components for rendering58- Next.js/Nuxt: Server components for data, client components for interactivity5960## Step 3: Handle All States6162Every component that deals with data needs these states:6364| State | What to show |65|-------|-------------|66| **Loading** | Skeleton, spinner, or placeholder. Not a blank screen. |67| **Error** | Clear message, retry action if possible. Not a crash. |68| **Empty** | Helpful message, maybe a CTA. Not "No results." with no context. |69| **Success** | The actual content. |70| **Partial** | Some data loaded, some still loading. Progressive rendering. |7172## Step 4: Accessibility7374This is a requirement, not a feature. Client work may have legal requirements (WCAG 2.1 AA).7576Non-negotiables:77- All interactive elements reachable by keyboard (Tab, Enter, Escape, Arrow keys)78- Semantic HTML elements (`button` not `div onClick`, `nav`, `main`, `article`)79- Form inputs have associated labels80- Images have alt text (or `alt=""` for decorative)81- Color contrast meets WCAG AA (4.5:1 for normal text, 3:1 for large text)82- Focus indicators visible83- Screen reader compatible (test with VoiceOver: Cmd+F5 on macOS)8485For detailed patterns, see `../codebase-audit/references/accessibility-checklist.md`.8687## Step 5: Performance8889Be conscious of what you ship:9091- **Lazy load** routes and heavy components (code splitting)92- **Optimize images**: correct size, modern format (WebP/AVIF), lazy loading93- **Avoid unnecessary re-renders**: memoize expensive computations, stable references for callbacks/objects in props94- **Monitor bundle size**: importing a whole library for one function is expensive95- **Virtualize long lists**: don't render 1000 DOM nodes when 20 are visible9697## Step 6: Verify9899When a URL is available, trigger the `chrome-devtools` skill to verify:100101- Console is clean (no errors, no warnings)102- Network requests are correct103- Visual output matches expectations (screenshot)104- Accessibility tree is correct105- Lighthouse scores are acceptable106- No layout shifts or jank