Claude-skill-registry frontend-design-standards
Use when generating React/TypeScript UI components, forms, layouts, or pages - prevents generic AI aesthetic, enforces accessibility, semantic HTML, theme compliance, minimum text sizes, proper states, and brand differentiation
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/frontend-design-standards" ~/.claude/skills/majiayu000-claude-skill-registry-frontend-design-standards && rm -rf "$T"
skills/data/frontend-design-standards/SKILL.mdFrontend Design Standards
Overview
AI-generated UI suffers from systematic failures: generic aesthetics, accessibility violations, div soup, small text, missing states, and brand blindness. This skill enforces production-quality standards that prevent the "AI look."
Core principle: Every component must pass accessibility, theming, responsiveness, and semantic HTML checks BEFORE considering the task complete.
Mandatory Checklist
Run through EVERY category for EVERY component. No exceptions.
1. Theme Compliance (Zero Hardcoded Colors)
FORBIDDEN - Tailwind color classes:
// WRONG - hardcoded colors className="bg-gray-50 text-gray-900 border-gray-200" className="bg-blue-600 text-white hover:bg-blue-700" className="text-green-500 bg-red-100"
REQUIRED - Theme variables:
// CORRECT - uses theme system className="bg-background text-foreground border-border" className="bg-primary text-primary-foreground hover:bg-primary/90" className="text-success bg-destructive/10"
FORBIDDEN - Hardcoded Hex Values:
// WRONG - magic numbers/colors className="bg-[#F3F4F6] text-[#111827]" style={{ backgroundColor: '#ff0000' }}
Verification:
# Find violations - any match is a failure grep -rn "bg-gray\|bg-blue\|bg-green\|bg-red\|text-gray\|text-blue" --include="*.tsx" grep -rn "#[0-9a-fA-F]\{3,6\}" --include="*.tsx" # Catch hex codes
If a semantic color doesn't exist, ADD IT to the theme system - don't use raw Tailwind colors or Hex values.
2. Typography Standards (16px Minimum Body Text)
FORBIDDEN:
// WRONG - below 16px minimum for readable content className="text-sm" // 14px - TOO SMALL for body className="text-xs" // 12px - TOO SMALL for any readable content
ALLOWED uses of small text:
- Timestamps, metadata, captions:
acceptabletext-sm - Legal disclaimers:
acceptabletext-xs - Labels for inputs:
acceptabletext-sm
Body text, paragraphs, descriptions MUST be:
className="text-base" // 16px - minimum className="text-lg" // 18px - preferred for long-form
Line height requirement:
// REQUIRED - 1.5 minimum for paragraphs className="leading-relaxed" // 1.625 className="leading-normal" // 1.5
3. Semantic HTML (No Div Soup)
FORBIDDEN - Generic divs for semantic content:
// WRONG <div className="navigation"> <div onClick={handleClick}>Home</div> </div>
REQUIRED - Proper semantic elements:
| Content Type | Required Element |
|---|---|
| Navigation | |
| Main content area | |
| Article/post | |
| Section with heading | |
| Side content | |
| Page footer | |
| Clickable action | |
| Form submission | |
| Navigation link | or Next.js |
| List of items | with |
| Headings | through in order |
Heading hierarchy rule: Never skip levels. After
<h2>, use <h3>, not <h4>.
4. Accessibility Requirements
Skip link for keyboard users (on page layouts):
// REQUIRED at top of page layouts <a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-background focus:text-foreground focus:ring-2 focus:ring-ring" > Skip to main content </a> // ... later <main id="main-content">
Every interactive element MUST have:
// Buttons with icons only <button aria-label="Close dialog" // REQUIRED for icon-only buttons type="button" > <X className="h-5 w-5" /> </button> // Toggle buttons <button aria-expanded={isOpen} // REQUIRED for expandable controls aria-controls="menu-id" // REQUIRED - ID of controlled element > // Form inputs <label htmlFor="email">Email</label> // REQUIRED - visible label <input id="email" aria-describedby="email-error" // REQUIRED when error present aria-invalid={hasError} // REQUIRED when validation fails /> <p id="email-error" role="alert">{error}</p> // Announced to screen readers
Focus management:
// REQUIRED - visible focus indicator className="focus:ring-2 focus:ring-ring focus:ring-offset-2" className="focus-visible:outline-none focus-visible:ring-2"
Color contrast: Verify all text meets WCAG AA (4.5:1 for normal text, 3:1 for large text).
Images require alt text:
// Informative image <img src="chart.png" alt="Sales increased 40% in Q3" /> // Decorative image (empty alt, not missing) <img src="decorative-swoosh.svg" alt="" role="presentation" /> // WRONG - missing alt <img src="product.jpg" /> // Screen readers say "image" with no context
5. Component States (No Happy Path Only)
Every component that loads data or accepts input MUST handle:
| State | Required Implementation |
|---|---|
| Loading | Skeleton or spinner with |
| Error | Error message with , retry action |
| Empty | Helpful empty state with action suggestion |
| Success | Confirmation with |
FORBIDDEN - Silent failures:
// WRONG - just logs to console } catch (error) { console.error(error); }
REQUIRED - User-visible feedback:
} catch (error) { setError("Failed to load. Please try again."); } // In render: {error && ( <div role="alert" className="text-destructive"> {error} <button onClick={retry}>Retry</button> </div> )}
6. Responsive Design Requirements
Touch target minimum:
// REQUIRED - 44px minimum for touch targets className="min-h-[44px] min-w-[44px]" // Or use padding to achieve: className="p-3" // 12px padding + content = ~44px
Mobile-first breakpoints:
// CORRECT - mobile first, add complexity upward className="flex flex-col md:flex-row" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3" // WRONG - desktop first with mobile overrides className="flex flex-row sm:flex-col" // Backwards
Required responsive considerations:
- Does navigation collapse to hamburger menu?
- Do touch targets meet 44px minimum?
- Does text remain readable without horizontal scroll?
- Do images have responsive sizing?
7. Brand Differentiation (Anti-Generic)
Before generating UI, ASK or DETERMINE:
- Color personality: What emotions should colors evoke?
- Typography character: Playful, professional, technical, luxurious?
- Shape language: Sharp/angular or soft/rounded?
- Density: Spacious/breathing or compact/efficient?
- Motion: Bouncy/playful or subtle/refined?
If brand requirements are vague, DO NOT default to:
- Gray backgrounds with blue accents
- Inter/system font with slate text
- Standard 3-column feature grids
- Purple gradients
Instead, ask: "What makes this brand/product unique? What should users FEEL?"
8. Motion and Micro-interactions (Anti-Dead Interface)
AI-generated UIs often feel "static" or "dead." Consider:
// Add meaningful transitions className="transition-colors duration-200" className="transition-transform hover:scale-105" // Loading feedback className="animate-pulse" // skeleton loading className="animate-spin" // spinner
Motion principles:
- Hover states on all interactive elements
- Transitions between states (not instant jumps)
- Loading indicators for async operations
- Success/error feedback animations
Don't overdo it: Subtle > flashy. Respect
prefers-reduced-motion.
9. Code Validity (No Hallucinations)
AI sometimes generates non-existent CSS properties or imports libraries/components that aren't installed.
FORBIDDEN - Hallucinated/obsolete CSS:
/* These don't exist */ width: fit-parent; text-fill-color: transparent; /* Obsolete vendor prefixes for modern properties */ -webkit-border-radius: 8px; /* Just use border-radius */
FORBIDDEN - Hallucinated Imports:
// WRONG - Do not import things that don't exist import { Sparkles } from '@heroicons/react/solid'; // Check if 'solid' exists in your version import { useMagicHook } from 'react-use'; // Check if 'react-use' is installed
Rule:
- Check
before importing a 3rd party library.package.json - Check file structure before importing local components (don't assume
exists).@/components/ui/card - Check MDN if unsure about a CSS property.
10. Project Structure (Anti-Monolith)
AI tends to dump everything into a single file. This is unmaintainable.
FORBIDDEN - The "God Component":
- Single file > 250 lines (unless it's a complex data table).
- Defining multiple complex sub-components in the same file.
- Mixing heavy business logic (
, data fetching) with UI rendering.useEffect
REQUIRED - Separation of Concerns:
- Extract Types: Move interfaces to
if shared, or top of file.types.ts - Extract Hooks: Move complex logic to
.useFeatureName.ts - Extract Components: If a sub-component renders > 20 lines of JSX, move it to its own file.
- Colocation: Keep related files together (e.g.,
,components/Feature/Feature.tsx
).components/Feature/useFeature.ts
Verification Checklist
Before marking any UI work complete, verify:
- Zero hardcoded Tailwind colors OR Hex codes (grep check passes)
- Body text uses
(16px) or largertext-base - Semantic HTML elements for all landmarks
- All interactive elements have accessible names
- Focus indicators visible on all interactive elements
- Loading, error, and empty states implemented
- Touch targets meet 44px minimum
- Mobile layout tested (or responsive classes verified)
- Brand differentiation considered (not generic gray/blue)
- Skip link present on page layouts
-
on all toggle buttonsaria-expanded - All images have alt text (empty for decorative)
- Hover/transition states on interactive elements
- No hallucinated CSS properties or Imports (verify existence)
- No "God Components" (>250 lines) - extracted sub-components
Common Rationalizations
| Excuse | Reality |
|---|---|
| "text-sm is fine for labels" | Labels yes, but body text/descriptions must be 16px+ |
| "Gray is neutral and professional" | Gray is also generic and forgettable. Ask about brand. |
| "I'll add accessibility later" | Later never comes. 80% of sites fail WCAG. Do it now. |
| "Loading states weren't requested" | Real apps have latency. Always include loading states. |
| "The design looks clean" | "Clean" often means "generic." Ask what makes it unique. |
| "Tailwind gray matches the theme" | Use theme variables. exists for this. |
| "Mobile can be handled later" | 60%+ traffic is mobile. Design mobile-first. |
| "Div works fine here" | Divs have no semantic meaning. Use proper elements. |
| "Client is waiting, no time to ask" | 5 min asking saves hours of rework. Ask about brand. |
| "Just console.error is fine" | Users see nothing. Always show visible error feedback. |
| "Skip link is overkill" | Keyboard users can't use your site without it. Required. |
| "I'll make it unique with colors" | Unique = structure + typography + spacing, not just hue. |
| "aria-label on every button is tedious" | Accessibility is not optional. Screen readers need it. |
| "Alt text can be added later" | Missing alt = broken for screen readers. Add it now. |
| "This CSS property should work" | If MDN doesn't have it, it doesn't exist. Check first. |
| "Animations are nice-to-have" | Static UIs feel dead. Basic transitions are required. |
Red Flags - Stop and Reconsider
If you catch yourself doing ANY of these, STOP:
- Using
,bg-gray-*
, or Hex codes (text-gray-*
)#F3F4F6 - Importing libraries without checking
package.json - Creating "God Components" (>250 lines) without splitting
- Body text smaller than 16px (
for paragraphs)text-sm - Interactive elements without accessible names
- No loading or error state handling
- All buttons/cards look identical
- Can't explain what makes this design unique
- No semantic landmarks (
,<nav>
,<main>
)<article> - Skip link not implemented for keyboard users
- Assuming brand requirements instead of asking
- Using
without user-visible feedbackconsole.error() - Missing
on toggle buttonsaria-expanded - Using
on divs instead of buttonsonClick - Images without alt attributes
- Using CSS properties you haven't verified exist
- No hover states or transitions on buttons/links
Quick Reference
Semantic Color Mapping
| Concept | Theme Variable | NOT This |
|---|---|---|
| Page background | | , |
| Card background | | , |
| Primary action | | , |
| Destructive | | , |
| Muted/secondary | | , |
| Borders | | |
| Main text | | , |
| Secondary text | | , |
Text Size Guide
| Usage | Class | Size | Line Height |
|---|---|---|---|
| Hero headline | to | 36-60px | |
| Section heading | to | 24-30px | |
| Card title | to | 18-20px | |
| Body text | | 16px | |
| Metadata only | | 14px | |
Essential ARIA Patterns
// Expandable content <button aria-expanded={open} aria-controls="content-id"> <div id="content-id" hidden={!open}> // Form error <input aria-invalid={!!error} aria-describedby="error-id" /> <p id="error-id" role="alert">{error}</p> // Loading content <div aria-busy={loading} aria-live="polite"> // Dynamic announcements <div role="status" aria-live="polite">{message}</div>