UI Component Spec — Design to Tailwind Handoff

    1

    Turn a component idea into a build-ready spec: props, variants, every state, tokens, the a11y contract, and the code.

    $9

    Secure checkout via Stripe

    Money-back guarantee

    Converts to your local currency at checkout

    Security scanned

    Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseDotsDots+21 more

    UI Component Spec — Design to Tailwind Handoff

    Example session with this skill installed

    Spec out a Toast/notification component for our React app. We use Tailwind and Radix, and we have semantic tokens already. Needs success, error and warning kinds, an optional action button, and it should stack when there are several.

    • Read your context and instructions
    • Compiled the ui component spec

    Toast

    Status: draft · Built on: Radix @radix-ui/react-toast · Owner: Design Systems

    Purpose

    A short, transient message confirming something happened or reporting that it didn't.

    Use when: the result isn't already visible on screen — a background job finished, a save failed, an item was deleted with an undo available.
    Don't use when: the user must act before continuing → use Dialog. The message belongs to one field → use inline error text. The state is permanent → use Banner.

    Anatomy

    ┌─ Root ──────────────────────────────────────────┐
    │ ┌Icon┐  ┌─ Title ──────────────┐  ┌─ Close ─┐  │
    │ └────┘  │ Description          │  └─────────┘  │
    │         └──────────────────────┘  ┌─ Action ─┐ │
    └───────────────────────────────────└──────────┘─┘
    
    PartRequiredNotes
    Root✅Radix Toast.Root; receives className and ...rest
    Icon—Derived from kind, 20px, aria-hidden="true"
    Title✅Radix Toast.Title, 1 line, truncates
    Description—Radix Toast.Description, max 2 lines
    Action—Radix Toast.Action, requires altText
    Close✅Radix Toast.Close, icon button
    Viewport✅One per app, rendered at root

    Props

    PropTypeDefaultReqDescription
    kind'success' | 'error' | 'warning' | 'info''info'—Sets icon, accent and live-region politeness
    titlestring—✅One line, ≤ 60 chars
    descriptionstring——≤ 140 chars
    action{ label: string; onClick: () => void; altText: string }——altText is required by Radix for screen readers
    durationnumber | null5000—null = never auto-dismiss
    onOpenChange(open: boolean) => void——
    classNamestring——Merged via twMerge onto Root

    Controlled/uncontrolled: uncontrolled by default via the useToast() hook; open + onOpenChange for controlled use.

    Variants

    successerrorwarninginfo
    IconCheckCircleAlertCircleAlertTriangleInfo
    Accent (left border 3px)--color-success--color-danger--color-warning--color-info
    Default duration5000null80005000
    rolestatusalertalertstatus

    DECISION NEEDED: should error auto-dismiss? Recommend

    no (duration: null) — an error the user didn't see is an error that gets reported as a bug. Overridable per call.

    States

    StateBackgroundBorderOther
    default--color-surface-raised1px --color-border, 3px left accentshadow --shadow-md
    hover--color-surface-raisedsametimer pauses (Radix default)
    focus-withinsamesametimer pauses; Close and Action show their own rings
    swipingsamesamefollows pointer X, 0.9 opacity
    stacked (2nd+)samesamesee Stacking

    Close / Action focus: focus-visible:ring-2 ring-focus ring-offset-2 ring-offset-surface-raised

    Sizing

    TokenValue
    min-width / max-width320px / 440px
    padding16px
    gap icon → text12px
    gap title → description2px
    radius--radius-md (6px)
    icon20px
    close target24×24 (meets WCAG 2.2 SC 2.5.8)
    viewport offset16px from edge; 24px ≥ 768px

    Typography

    Title 14px / 600 / 1.4 · Description 14px / 400 / 1.5, --color-text-muted · Action 14px / 600
    Title truncates at 1 line; description clamps at 2 (line-clamp-2).

    Stacking

    • Max 3 visible; older ones collapse behind with translateY(-8px) scale(0.97) per level.
    • New toasts enter at the front. Queue beyond 3 — don't drop.
    • Hovering the stack expands it to full height.
    • Toast.Viewport is the single source of stacking order — don't manage it per toast.

    Accessibility

    Element: Radix Toast.Root → renders <li> inside the viewport's <ol>.
    Live region: the viewport is the live region and must be in the DOM before any toast is inserted. role="status" for success/info (polite), role="alert" for error/warning (assertive).

    KeyAction
    F8Focus the toast viewport (Radix hotkey)
    TabMove through Action, then Close
    EscapeDismiss focused toast

    Focus: toasts never steal focus. Focus returns to where it was on dismiss.
    Announcements: action.altText is what a screen reader hears — write it as an instruction ("Press F8 then Enter to undo"), not a repeat of the label.
    Reduced motion: slide-in and swipe become a 120ms opacity fade; stacking offset applies instantly with no transition.

    Behaviour

    • Timer pauses on hover, focus-within, and when the tab is backgrounded.
    • Identical consecutive toasts collapse into one with a count badge rather than stacking duplicates.
    • Action click dismisses the toast unless onClick returns false.
    • Swipe right dismisses on touch; 80px threshold.

    Responsive

    BreakpointChange
    < 640pxFull width minus 32px, anchored bottom, swipe down to dismiss
    ≥ 640px320–440px, anchored bottom-right, swipe right

    Implementation

    const toast = cva(
      'pointer-events-auto relative flex w-full items-start gap-3 rounded-md border ' +
      'border-l-[3px] bg-surface-raised p-4 shadow-md ' +
      'data-[state=open]:animate-in data-[state=open]:slide-in-from-bottom-2 ' +
      'data-[state=closed]:animate-out data-[state=closed]:fade-out-80 ' +
      'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] ' +
      'motion-reduce:animate-none motion-reduce:transition-none',
      {
        variants: {
          kind: {
            success: 'border-l-success',
            error:   'border-l-danger',
            warning: 'border-l-warning',
            info:    'border-l-info',
          },
        },
        defaultVariants: { kind: 'info' },
      }
    )
    
    const ICON = { success: CheckCircle, error: AlertCircle, warning: AlertTriangle, info: Info }
    const POLITENESS = { success: 'status', error: 'alert', warning: 'alert', info: 'status' } as const
    
    <Toast.Root className={cn(toast({ kind }), className)}
                duration={duration} role={POLITENESS[kind]} {...rest}>
      <Icon className="mt-0.5 size-5 shrink-0" aria-hidden="true" />
      <div className="min-w-0 flex-1">
        <Toast.Title className="truncate text-sm font-semibold">{title}</Toast.Title>
        {description && (
          <Toast.Description className="mt-0.5 line-clamp-2 text-sm text-muted">
            {description}
          </Toast.Description>
        )}
      </div>
      {action && (
        <Toast.Action altText={action.altText} asChild>
          <button className="shrink-0 text-sm font-semibold text-primary
                             focus-visible:outline-none focus-visible:ring-2
                             focus-visible:ring-focus focus-visible:ring-offset-2">
            {action.label}
          </button>
        </Toast.Action>
      )}
      <Toast.Close className="shrink-0 rounded p-0.5 text-muted hover:text-text
                              focus-visible:outline-none focus-visible:ring-2
                              focus-visible:ring-focus" aria-label="Dismiss">
        <X className="size-4" />
      </Toast.Close>
    </Toast.Root>
    

    Test cases

    • Each kind renders the right icon, accent and role
    • Error toast does not auto-dismiss
    • Timer pauses on hover and on focus-within
    • F8 → Tab → Enter fires the action
    • Escape dismisses the focused toast only
    • 4th toast queues rather than dropping
    • 200-character description clamps to 2 lines, no overflow
    • prefers-reduced-motion removes slide and swipe animation
    • Contrast passes for all four accents in light and dark
    • Close button target ≥ 24×24

    Open decisions

    • DECISION NEEDED: error auto-dismiss — recommend null (see Variants).
    • DECISION NEEDED: do we need a loading toast for long jobs? Recommend no — use an inline progress indicator; a toast that lives for 40s isn't a toast.

    Connects securely to your tools. The creator never sees your data.

    About this skill

    The problem

    "Here's the design" is where most handoffs end, and where the six-question Slack thread begins. What are the props? What happens on hover? What about disabled and loading at the same time? What's the keyboard behaviour? Half of it gets guessed, and the guesses diverge across the codebase.

    What it does

    • Produces a full component spec: purpose and when not to use it, named anatomy, a real props table, a variant by size grid with invalid combinations marked, every state with its exact token, sizing, typography and responsive behaviour.
    • Writes the accessibility contract — correct element, keyboard table, focus management, ARIA, reduced-motion fallback — using the WAI-ARIA patterns for the twelve components this comes up for most.
    • Gives real implementation code: cva variants, twMerge overrides, semantic tokens instead of hex values, focus-visible instead of focus.
    • Flags genuinely open questions as DECISION NEEDED with a recommendation, rather than silently picking.

    Why this beats prompting it yourself

    A spec is only useful if it's complete, and completeness is exactly what a freeform answer misses. This enforces the sections that get skipped — the invalid variant combinations, the disabled-and-loading interaction, where focus goes on close. It also extends what you already use rather than reinventing it: if you're on Radix or shadcn, it specs the visual layer and says which primitive handles the rest.

    Use cases

    • Adding a component to a design system and wanting it documented once, properly
    • Handing a design to an engineer who isn't in the room
    • Building a component yourself and wanting the states enumerated before you start
    • Reviewing an existing component for what's missing

    Known limitations

    Tailwind and React are the default examples; other stacks are supported but get less idiomatic code. Doesn't generate visual designs — it specs decisions already made.

    Requires context on existing UI libraries (e.g., Radix, shadcn) and design tokens to avoid hard-coded values. Focused on web-based UI components.

    How to use

    1. 1

      Connect your agent to the Agensi MCP

      Copy the prompt and paste it into Claude, ChatGPT, Cursor or any agent that supports MCP. It sets up the connection for you. Manual setup

    2. 2

      Sign in to Agensi

      Your agent shows a sign-in link. Sign in and click Allow.

    3. 3

      Ask for what you need

      Your agent loads this skill and uses it on your task. It always asks before any payment.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill goes through the trust checks below.

    Security scanned

    Checked by our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Money-back guarantee

    Doesn't do what its page promises? You get your money back.

    Trust & safety

    Security scan

    Security scan passed 1 month ago

    Permissions

    No special permissions declared or detected

    Listed1 month ago

    What's inside

    Frequently Asked Questions

    This skill acts as a bridge between design and code by generating an exhaustive technical specification, including a props table, variant grids, accessibility contracts, and Tailwind-ready implementation code, ensuring nothing is left to guesswork during handoff.

    While optimized for React and Tailwind CSS (including class-variance-authority and shadcn patterns), the skill can be adapted to other frameworks, though the code output will be most idiomatic for the React ecosystem.

    No, this skill is a documentation and logic engine. It requires you to provide the component concept or design details, which it then translates into a structured technical blueprint for your engineers.

    The skill provides a full WAI-ARIA accessibility contract, specifying the correct HTML elements, keyboard interaction tables, focus management logic, and ARIA roles required for a compliant component.

    Once you add this skill to your AI agent, you can start by describing a component or uploading a design summary; the agent will then guide you through the spec generation process following its built-in framework.

    New in Frontend & Web Apps