Skip to content

Component Specification Protocol

Cindy Zhang edited this page Jun 23, 2026 · 1 revision

Component Specification Protocol

New here? Start with Component Lifecycle for the full end-to-end guide. This page covers the specification phase in detail.

Every new Astryx component must go through the full specification protocol before any code is written. The spec is the contract — deviations during build need justification.


Phase 1: Triage

  • Identify the component gap (from internal usage data, builder feedback, or milestone needs)
  • Check if existing components can compose to solve the problem before creating something new
  • If the need is domain-specific, it's a recipe/example — not a core component

Phase 2: Research — Internal

  • Use code search (tbgs, tbgf, tbcs, zbgs) to study the internal implementation
  • Gather: current API, prop types, internal architecture, delegation patterns
  • Usage analysis: which props are actually used, how frequently, what the common patterns are
  • Identify the value to port — not the internal structure. Internal architecture reflects internal constraints that may not apply to OSS

Phase 3: Research — External

  • Compare with equivalent components in other design systems (Radix, shadcn, Ant, MUI, Chakra)
  • Note naming conventions, API patterns, slot flexibility
  • Identify where the industry has converged vs. where there's meaningful divergence

Phase 4: Enumerate Use Cases

Before proposing an API, exhaustively list the scenarios it must handle. This prevents designing for the happy path and discovering gaps during build.

Every component should cover at minimum:

Case What it tests
Simple/default The 80% use case. Zero config. Does it just work?
Configured Custom options beyond defaults. Does configuration feel natural?
Controlled External state management. Can the consumer own the state?
Composed Inside Dialog, Table, AppShell, Card. Does it play well with siblings?
Edge/mixed Mixed modes, dynamic switching, responsive behavior — the scenario that reveals friction
Migration What does adopting this look like for someone with nothing today?

Add domain-specific cases as needed. The use case list becomes the test battery for API Arbitration and the acceptance criteria during build.

Phase 5: Draft Spec

Write the spec document covering:

  • The problem — what gap this fills, with usage data
  • Use cases — the full enumeration from Phase 4
  • Architecture — how it composes with existing components, delegation hierarchy
  • API — props, types, defaults, with rationale for each decision
  • Behavior — interaction patterns, keyboard, accessibility, state management
  • Key decisions — tradeoffs made and why, with alternatives considered
  • Composition stories — how it works inside Dialog, Table, Card, List, AppShell

Phase 6: Surface Area Audit

Before review, map every proposed export against what already exists in Astryx:

  • Flag any sub-component that duplicates an existing component (e.g., Separator = Divider)
  • Identify anything useful outside this component family as a standalone extraction (e.g., Kbd)
  • Challenge thin wrappers — if it's just styling an existing component, use the existing component

Phase 7: Spec Review

Apply the spec review protocol (6 phases):

7a. Read & Understand

  • Read the full spec
  • Identify which component family this belongs to (alerting, input/form, action/menu, navigation/data, layout)

7b. Cross-Reference

  • Compare prop names against the RIGHT component family (not random components)
  • Check existing Astryx naming conventions:
Pattern Convention Examples
Primary callback onChange TabList, Selector, Switch
Visual mode variant Button, Badge, Banner
Accessible name label Button, Popover, MoreMenu
Flexible end slot endContent ListItem, SideNavItem, TopNav
Input validation status: {type, message} Field, TextInput
Async action onChangeAction Selector, Switch

7c. Competitive Analysis

  • Do prop names match industry conventions?
  • Any naming collisions with natural language priors?
  • What do Radix, shadcn, Ant, MUI, Chakra call the equivalent?

7d. Apply Principles

  • Positional > semantic for flexible slots (endContent not action)
  • Relax slots for OSS — don't restrict to string when ReactNode works
  • No premature flexibility — drop props with 0 usage and no external precedent
  • Skip sub-components that duplicate existing ones
  • Name for humans, describe for machines — human-friendly name, keyword-rich description
  • Don't fight natural language priors

7e. Composition & Defaults

  • How does this compose with Dialog, Table, Card, List, AppShell?
  • Are defaults right? (Override rate = 0% means right default)

7f. Resolve Uncertainty

  • Flag anything uncertain for vibe test
  • Don't debate in the abstract — build it, test it, feel the friction

Phase 8: API Arbitration

API shape is determined through API Arbitration — the standard process, not an optional step for contentious cases.

  • Explore candidate API shapes (Phase 1 of arbitration)
  • Enumerate all use cases the API must handle (Phase 2)
  • Test candidates with naive prompts against skill docs (Phase 3)
  • Iterate until a clear winner emerges or the team makes a call (Phase 4)
  • Measure: override rate (0% = right default), correctness rate, escape hatches, hallucinations

Contributors are expected to drive this work. The team collaborates in the issue thread and applies system-level context. See API Arbitration for the full process and sample prompt.

Phase 9: Finalize Spec

  • Update spec with review feedback and vibe test results
  • Create or update tracking issue
  • Spec is now the source of truth for the build loop → proceed to Component Build Protocol

Key Principles (ranked by impact)

  1. Compose, don't rebuild — use existing Astryx components, don't reimplement
  2. Family alignment > global consistency — compare within the right component family
  3. Positional prop names > semantic for flexible slots
  4. Natural language priors are incredibly strong — work with them, not against them
  5. Vibe test when unsure — override rate is the cleanest signal
  6. Internal architecture ≠ OSS architecture — port the value, not the structure
  7. Relax slots for OSS — ReactNode where possible
  8. The override rate is the best signal — 0% = right default, 67% = wrong default

Clone this wiki locally