Claude-skill-registry design-to-component-translator
Converts Figma/design specifications into production-ready UI components with accurate spacing, typography, color tokens, responsive rules, and interaction states (hover, focus, disabled, active). Generates Tailwind/shadcn code with design system tokens mapping. Use when translating "Figma to code", "design specs to components", or "implement design system".
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/design-to-component-translator" ~/.claude/skills/majiayu000-claude-skill-registry-design-to-component-translator && rm -rf "$T"
manifest:
skills/data/design-to-component-translator/SKILL.mdsource content
Design-to-Component Translator
Convert design specifications into pixel-perfect, production-ready React components.
Core Workflow
- Analyze design specs: Extract spacing, colors, typography, dimensions
- Map to tokens: Convert design values to design system tokens
- Generate structure: Create semantic HTML structure
- Apply styles: Implement Tailwind/CSS with exact measurements
- Add states: Include hover, focus, active, disabled states
- Handle responsive: Implement breakpoint-specific rules
- Ensure accessibility: Add ARIA labels, keyboard navigation
- Document variants: List all visual states and props
Design Spec Analysis
Extract from Figma/Design
Spacing & Layout:
- Padding:
(16px),p-4
(24px horizontal)px-6 - Margin:
(8px),m-2
(16px top)mt-4 - Gap:
(12px between flex items)gap-3 - Width/Height:
(256px),w-64
(40px)h-10
Typography:
- Font family:
,font-sansfont-mono - Font size:
(14px),text-sm
(16px),text-base
(18px)text-lg - Font weight:
(400),font-normal
(500),font-medium
(600)font-semibold - Line height:
,leading-tight
,leading-normalleading-relaxed - Letter spacing:
,tracking-tight
,tracking-normaltracking-wide
Colors:
- Background:
,bg-blue-500bg-gray-100 - Text:
,text-gray-900text-white - Border:
,border-gray-300border-blue-600 - Opacity:
,bg-opacity-50text-opacity-75
Borders & Radius:
- Border width:
,border
,border-2border-t-4 - Border radius:
(4px),rounded
(6px),rounded-md
(8px),rounded-lgrounded-full
Shadows:
,shadow-sm
,shadow
,shadow-md
,shadow-lgshadow-xl
Design Token Mapping
Create Token System
// tokens.ts export const tokens = { colors: { primary: { 50: "#eff6ff", 100: "#dbeafe", 500: "#3b82f6", 600: "#2563eb", 700: "#1d4ed8", }, gray: { 100: "#f3f4f6", 300: "#d1d5db", 500: "#6b7280", 700: "#374151", 900: "#111827", }, }, spacing: { xs: "0.25rem", // 4px sm: "0.5rem", // 8px md: "1rem", // 16px lg: "1.5rem", // 24px xl: "2rem", // 32px }, fontSize: { xs: ["0.75rem", { lineHeight: "1rem" }], sm: ["0.875rem", { lineHeight: "1.25rem" }], base: ["1rem", { lineHeight: "1.5rem" }], lg: ["1.125rem", { lineHeight: "1.75rem" }], xl: ["1.25rem", { lineHeight: "1.75rem" }], }, borderRadius: { sm: "0.25rem", // 4px md: "0.375rem", // 6px lg: "0.5rem", // 8px full: "9999px", }, shadows: { sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)", md: "0 4px 6px -1px rgb(0 0 0 / 0.1)", lg: "0 10px 15px -3px rgb(0 0 0 / 0.1)", }, };
Tailwind Config
// tailwind.config.js module.exports = { theme: { extend: { colors: { primary: { 50: "#eff6ff", 100: "#dbeafe", 500: "#3b82f6", 600: "#2563eb", 700: "#1d4ed8", }, }, spacing: { 18: "4.5rem", 88: "22rem", }, fontSize: { "2xs": "0.625rem", }, }, }, };
Component Translation Examples
Button from Figma Spec
Figma Specs:
- Height: 40px
- Padding: 12px 24px
- Border radius: 6px
- Font: Inter Medium 14px
- Background: #3B82F6
- Text: #FFFFFF
- Hover: #2563EB
- Shadow: 0 1px 3px rgba(0,0,0,0.1)
Translated Component:
import { cn } from "@/lib/utils"; interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant?: "primary" | "secondary"; size?: "sm" | "md" | "lg"; } export const Button = ({ variant = "primary", size = "md", className, children, ...props }: ButtonProps) => { return ( <button className={cn( // Base styles "inline-flex items-center justify-center rounded-md font-medium", "transition-colors duration-200", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50", // Variant: Primary (matches Figma) variant === "primary" && [ "bg-primary-500 text-white shadow-sm", "hover:bg-primary-600", "active:bg-primary-700", ], // Size: Medium (40px height, 12px 24px padding) size === "md" && "h-10 px-6 text-sm", className )} {...props} > {children} </button> ); };
Card from Design Spec
Figma Specs:
- Padding: 24px
- Border radius: 12px
- Background: #FFFFFF
- Border: 1px solid #E5E7EB
- Shadow: 0 1px 3px rgba(0,0,0,0.1)
- Max width: 400px
Translated Component:
interface CardProps extends React.HTMLAttributes<HTMLDivElement> { elevated?: boolean; } export const Card = ({ elevated = false, className, children, ...props }: CardProps) => { return ( <div className={cn( // Base from Figma "max-w-sm rounded-xl bg-white p-6", "border border-gray-200", // Conditional shadow elevated ? "shadow-lg" : "shadow-sm", // Hover state (not in Figma, but good UX) "transition-shadow duration-200 hover:shadow-md", className )} {...props} > {children} </div> ); };
Interaction States
Hover States
// Figma: Background changes from #3B82F6 to #2563EB on hover className={cn( 'bg-primary-500', 'hover:bg-primary-600', 'transition-colors duration-200' )}
Focus States
// Accessible focus ring className={cn( 'focus:outline-none', 'focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2' )}
Active/Pressed States
// Figma: Slightly darker on click className={cn( 'active:bg-primary-700', 'active:scale-[0.98]', // Slight scale down 'transition-all duration-100' )}
Disabled States
// Figma: 50% opacity, no interactions className={cn( 'disabled:opacity-50', 'disabled:cursor-not-allowed', 'disabled:pointer-events-none' )}
Responsive Design Translation
Breakpoint Mapping
// Figma artboards → Tailwind breakpoints // Mobile (375px): default (no prefix) // Tablet (768px): md: // Desktop (1024px): lg: // Wide (1280px): xl: <div className={cn( // Mobile: Stack vertically, full width "flex flex-col gap-4 w-full", // Tablet: Side by side, 50% each "md:flex-row md:gap-6", // Desktop: Max width container "lg:max-w-6xl lg:mx-auto" )} />
Responsive Typography
// Figma mobile: 14px, desktop: 16px <h1 className="text-sm md:text-base lg:text-lg font-semibold"> Responsive Heading </h1>
Responsive Spacing
// Figma mobile: 16px padding, desktop: 24px <div className="p-4 md:p-6 lg:p-8">Content</div>
Design System Integration
Using shadcn/ui Patterns
// Leveraging shadcn's composable approach import { cn } from "@/lib/utils"; const buttonVariants = cva( "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "underline-offset-4 hover:underline text-primary", }, size: { default: "h-10 py-2 px-4", sm: "h-9 px-3 rounded-md", lg: "h-11 px-8 rounded-md", icon: "h-10 w-10", }, }, defaultVariants: { variant: "default", size: "default", }, } );
Color System Translation
From Figma to CSS Variables
/* Figma colors → CSS variables */ :root { /* Primary from Figma #3B82F6 */ --primary: 221 83% 60%; --primary-foreground: 0 0% 100%; /* Secondary from Figma #6B7280 */ --secondary: 220 9% 46%; --secondary-foreground: 0 0% 100%; /* Backgrounds */ --background: 0 0% 100%; --foreground: 222 47% 11%; /* Borders */ --border: 220 13% 91%; --input: 220 13% 91%; --ring: 221 83% 60%; /* Radius from Figma */ --radius: 0.5rem; }
Using in Components
<div className="bg-background text-foreground border-border"> <button className="bg-primary text-primary-foreground">Button</button> </div>
Animation & Transitions
Micro-interactions from Figma
// Figma: Button scales slightly on hover <button className={cn( 'transition-all duration-200', 'hover:scale-105', 'active:scale-95' )}> Hover me </button> // Figma: Card lifts on hover <div className={cn( 'transition-all duration-300', 'hover:-translate-y-1 hover:shadow-lg' )}> Card content </div> // Figma: Fade in on mount <div className="animate-in fade-in duration-500"> Fading content </div>
Measurement Conversion
Figma Pixels → Tailwind Classes
| Figma | Tailwind | Value |
|---|---|---|
| 2px | 0.5 | 0.125rem |
| 4px | 1 | 0.25rem |
| 8px | 2 | 0.5rem |
| 12px | 3 | 0.75rem |
| 16px | 4 | 1rem |
| 20px | 5 | 1.25rem |
| 24px | 6 | 1.5rem |
| 32px | 8 | 2rem |
| 40px | 10 | 2.5rem |
| 48px | 12 | 3rem |
Custom Values
// Figma: 18px (not in default Tailwind) <div className="w-[18px] h-[18px]">{/* or add to config */}</div>
Accessibility Mapping
From Visual Design to A11y
// Figma shows disabled state <button disabled={isDisabled} aria-disabled={isDisabled} className={cn( isDisabled && 'opacity-50 cursor-not-allowed' )} > Submit </button> // Figma shows error state <input aria-invalid={hasError} aria-describedby={hasError ? 'error-message' : undefined} className={cn( hasError && 'border-red-500 focus:ring-red-500' )} />
Common Patterns
Form Input Translation
Figma Specs:
- Height: 44px
- Padding: 12px 16px
- Border: 1px #D1D5DB
- Border radius: 8px
- Focus border: 2px #3B82F6
<input className={cn( "h-11 w-full rounded-lg border border-gray-300 px-4", "text-base text-gray-900 placeholder:text-gray-500", "focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-0", "disabled:cursor-not-allowed disabled:opacity-50" )} />
Icon Button Translation
Figma Specs:
- Size: 40x40px
- Icon: 20x20px centered
- Border radius: 8px
- Background hover: #F3F4F6
<button className={cn( "flex h-10 w-10 items-center justify-center rounded-lg", "text-gray-700 transition-colors", "hover:bg-gray-100", "focus-visible:ring-2 focus-visible:ring-primary-500" )} > <Icon className="h-5 w-5" /> </button>
Best Practices
- Measure twice: Verify all measurements match Figma exactly
- Use design tokens: Map to tokens, not hardcoded values
- All states: Include hover, focus, active, disabled, error
- Responsive: Implement all breakpoints from design
- Accessibility: Add ARIA where Figma shows states
- Animations: Match transition timings to design
- Dark mode: If designs exist, implement with class variants
- Component variants: Create reusable variant props
- Documentation: Note any deviations from design
- Review: Get designer approval on implementation
Output Checklist
Every design-to-component translation should include:
- Exact spacing matching Figma measurements
- Typography scales and weights
- All color values from design system
- Border radius and shadows
- Hover state styling
- Focus state styling (accessible)
- Active/pressed state styling
- Disabled state styling
- Responsive breakpoint rules
- Design token mapping documented
- Accessibility attributes
- Component variants for states