Spec Schema

Component specs are framework-agnostic YAML files that define a component's API, structure, behaviour, and keyboard interactions. The AI agent generates these before writing any code.

format v1This page documents spec format version 1. Specs declare the version they follow via specVersion; a spec without one reads as version 1. The version bumps only for a breaking change to the format itself: new optional fields never bump it, so version 1 grows backwards-compatibly.

Purpose

Specs serve as the source of truth for what a component does, independent of how it's implemented. The same spec can drive component generation across React, Vue, Lit, Svelte, or any custom platform.

Specs live in specs/*.spec.yaml at the project root.

Recipe Specs

Recipes are non-exported Storybook compositions for full page mockups, flows, dashboards, settings pages, and other examples that show how exported components work together. Recipe specs live in specs/recipes/*.recipe.yaml.

name: SettingsPage
type: recipe
exported: false
description: A full settings page composition using existing primitives.
intent: |
  Demonstrates how Card, Heading, Button, and form controls combine into a dense settings screen.
components:
  - Card
  - Heading
  - Button
scenarios:
  - name: Default
    description: Account profile and notification settings with save actions.
decisions:
  - decision: Recipe uses existing Button and Card components
    rationale: Keeps the example focused on composition instead of creating new reusable primitives.

Top-Level Fields

FieldTypeDescription
specVersionintegerSpec format version (currently 1; absent reads as 1)
namestringPascalCase component name (e.g., "AlertDialog")
statusstringLifecycle: draft, experimental, stable, or deprecated
descriptionstringBrief description of the component's purpose
intentstringWhat the component is for, when to use it, and how it differs from adjacent components
usageobjectStructured do/avoid guidance, with pointers at the better alternative
decisionsarrayDesign decisions with their rationale, the reasoning that travels with the spec
apiobjectProps and events definitions
compositionobjectComponent dependencies (lists other components used)
structureobjectRegions, slots, and layout hints
behaviourobjectState machines and interactions
keyboardobjectKeyboard interaction bindings
accessibilityobjectARIA semantics, focus rules, announcements, motion and contrast constraints

api

api.props

Each prop is defined with a type, optional enum of allowed values, and a default:

api:
  props:
    variant:
      type: string
      enum: [primary, secondary, danger, ghost]
      default: primary
      description: Visual style variant
    size:
      type: string
      enum: [sm, md, lg]
      default: md
    disabled:
      type: boolean
      default: false

api.events

Events the component can emit, with optional payload types:

api:
  events:
    onClick:
      description: Fired when the button is clicked
      payload: MouseEvent
    onDismiss:
      description: Fired when the component is dismissed

composition

Declares which other components this component depends on:

composition:
  uses:
    - Button
    - Icon
    - Badge

structure

Describes the component's internal layout in framework-agnostic terms:

structure:
  regions:
    - name: header
      element: div
      description: Top section with title and close button
    - name: body
      element: div
      description: Main content area
  slots:
    - name: children
      description: Main content slot
    - name: footer
      description: Optional footer actions

behaviour

Defines state machines and interactions using a trigger/guard/effect model:

behaviour:
  states:
    - idle
    - open
    - closing
  interactions:
    - trigger: click
      guard: "state === 'idle'"
      effect: "setState('open')"
    - trigger: escape
      guard: "state === 'open'"
      effect: "setState('closing')"

keyboard

Accessibility keyboard bindings, independent of framework:

keyboard:
  bindings:
    - key: Enter
      action: activate
      description: Activates the button
    - key: Space
      action: activate
      description: Activates the button
    - key: Escape
      action: dismiss
      description: Closes the dialog

usage

Structured do/don't guidance, the checkable form of intent. Each avoid entry can point at the component that fits better:

usage:
  do:
    - Surface short, non-blocking confirmation after a user action
  avoid:
    - situation: Errors the user must acknowledge before continuing
      instead: Alert
      why: Toasts auto-dismiss, so an unacknowledged error can be missed.

accessibility

The accessibility contract beyond keyboard bindings: ARIA semantics, focus management, screen reader announcements, and motion/contrast constraints. Every platform rendering is built from these fields, so assistive-technology behaviour stays identical across React, Vue, Lit, and the rest.

accessibility:
  aria:
    - element: root
      role: alert
      attributes: aria-live="assertive" aria-atomic="true"
      rationale: Errors interrupt the screen reader; info toasts use "polite".
  focus:
    - Opening the toast never steals focus from the user's current task
  announcements:
    - trigger: toast appears
      message: The toast's text content
      politeness: polite
  reducedMotion: Replace the slide-in animation with an opacity fade.
  contrast: All variants meet WCAG AA (4.5:1) against their token backgrounds.

Full Example

# specs/button.spec.yaml

specVersion: 1
name: Button
status: stable
description: Interactive button with multiple variants and sizes

api:
  props:
    variant:
      type: string
      enum: [primary, secondary, danger, ghost]
      default: primary
    size:
      type: string
      enum: [sm, md, lg]
      default: md
    disabled:
      type: boolean
      default: false
    loading:
      type: boolean
      default: false
  events:
    onClick:
      description: Fired on click when not disabled or loading
      payload: MouseEvent

composition:
  uses:
    - Icon

structure:
  regions:
    - name: root
      element: button
      description: The button element
  slots:
    - name: children
      description: Button label content
    - name: icon
      description: Optional leading icon

behaviour:
  states:
    - idle
    - hover
    - active
    - loading
    - disabled
  interactions:
    - trigger: click
      guard: "!disabled && !loading"
      effect: "emit('onClick')"

keyboard:
  bindings:
    - key: Enter
      action: activate
    - key: Space
      action: activate