Skip to main content
Marco Rossi·

From a Figma description to an accessible, fully-typed React component

Creates a complete, accessible, responsive UI component from a design description or Figma-like specification.

Frontend Component from Design Spec

You are a senior frontend engineer building a production-grade UI component. Implement based on the design spec below. ## Design Specification {{design_specification}} ## Technical Requirements - Framework: {{frontend_framework}} (React, Vue, Angular, Svelte) - Styling: {{styling_approach}} (CSS Modules, Styled Components, Tailwind, SCSS) - Component library: {{component_library}} (MUI, shadcn, Ant Design, none) - Accessibility: WCAG 2.1 AA minimum - Responsive: Mobile-first, breakpoints at 640px, 768px, 1024px, 1280px ## Component Requirements 1. **Main Component** - Complete implementation with: - Props interface with JSDoc comments - Proper TypeScript types - Forward refs where appropriate - Composition pattern support - Loading and error states - Empty state handling 2. **Sub-components** - Any logical child components 3. **Custom Hooks** - Extract reusable logic into hooks 4. **Storybook Story** - For component documentation/testing 5. **Unit Tests** - Using {{testing_library}}, cover interactions and a11y 6. **CSS/Styling** - Complete styles matching the spec Follow {{frontend_framework}} best practices. Ensure keyboard navigation and screen reader compatibility. Avoid unnecessary re-renders. Export named components with proper displayName.

Ergebnisse

Accessible, fully-typed `<Rating>` component — keyboard navigable, WCAG 2.1 AA, no library. ```tsx import { useId, useState, type KeyboardEvent } from "react"; interface RatingProps { /** Current value, 0–max. Controlled when provided. */ value?: number; max?: number; onChange?: (value: number) => void; label?: string; } export function Rating({ value, max = 5, onChange, label = "Rating" }: RatingProps) { const [hover, setHover] = useState<number | null>(null); const groupId = useId(); const active = hover ?? value ?? 0; const onKey = (e: KeyboardEvent, star: number) => { if (e.key === "ArrowRight" || e.key === "ArrowUp") onChange?.(Math.min(max, star + 1)); if (e.key === "ArrowLeft" || e.key === "ArrowDown") onChange?.(Math.max(1, star - 1)); }; return ( <div role="radiogroup" aria-label={label} className="inline-flex gap-1"> {Array.from({ length: max }, (_, i) => i + 1).map((star) => ( <button key={`${groupId}-${star}`} role="radio" aria-checked={star === value} aria-label={`${star} of ${max}`} tabIndex={star === (value || 1) ? 0 : -1} onClick={() => onChange?.(star)} onKeyDown={(e) => onKey(e, star)} onMouseEnter={() => setHover(star)} onMouseLeave={() => setHover(null)} className={star <= active ? "text-amber-400" : "text-zinc-600"} > ★ </button> ))} </div> ); } Rating.displayName = "Rating"; ``` Roving `tabIndex` + arrow-key handling means screen-reader and keyboard users get a proper radio group, not a pile of buttons.

Modell: Claude Sonnet 4

11 Likes2 SavesScore: 6

1 Kommentar

Ahmed Hassan·

This is going in our internal wiki, thanks for sharing.