# Component Library Design: Headless and Token-First

Source: https://www.techinterview.org/post/3233475193/component-library-design-headless-tokens/
Updated: 2026-07-12 · techinterview.org

Building a component library is one of the highest-impact frontend specialties. A good library compounds across the entire org. A bad one becomes a liability that engineers route around. Senior frontend interviews probe whether you understand the modern patterns, particularly the headless and token-first approaches that dominate 2026.

## The headless library era

Pre-2022: component libraries were styled (Material UI, Bootstrap, Ant Design). You got a Button with built-in styles.

2022+: headless libraries provide behavior without styles. You bring your own design.

Examples:

- Radix UI is the dominant React headless library

- React Aria is Adobe's offering, deeply accessible

- Headless UI is Tailwind-paired

- Ark UI is framework-agnostic (Vue, React, Solid)

Build your library on top of these; you get accessibility for free, focus your design effort on the visual layer.

## Why headless wins

- Accessibility: keyboard nav, ARIA, focus management — done right by experts

- Behavior: complex state machines (combobox, tabs, dialog)

- Customization: you control every visual aspect

- Smaller bundles: only what you use

## Token-first design

Define tokens before components:

- Color: primitive (gray.500) and semantic (text.primary)

- Spacing: scale (1, 2, 3 = 4px, 8px, 12px)

- Typography: scale, font, line-height

- Radius, elevation, motion

Tokens stored in JSON; build pipeline emits CSS variables, Sass, JS objects. Style Dictionary is the standard tool.

## Theming via tokens

Themes (light/dark, brand variants) are different mappings of semantic tokens to primitives:

- Light: text.primary → gray.900

- Dark: text.primary → gray.100

Components consume semantic tokens. Switching theme switches the underlying mapping.

## Composing components

Modern pattern: compound components.


```
<Tabs.Root>
  <Tabs.List>
    <Tabs.Trigger value="a">A</Tabs.Trigger>
    <Tabs.Trigger value="b">B</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="a">...</Tabs.Content>
  <Tabs.Content value="b">...</Tabs.Content>
</Tabs.Root>
```


Beats opaque `<Tabs items={...} />` APIs because you can customize any sub-part.

## Variants

Common pattern: components have variants (size, color, intent):


```
<Button variant="primary" size="md">Save</Button>
```


Implement with a function that maps variants to classes:


```
const buttonVariants = cva(
  "inline-flex items-center font-medium",
  {
    variants: {
      variant: {
        primary: "bg-blue-600 text-white",
        secondary: "bg-gray-200 text-gray-900"
      },
      size: { sm: "px-2 py-1", md: "px-4 py-2", lg: "px-6 py-3" }
    }
  }
);
```


Library: `class-variance-authority` (CVA) is the standard.

## Documentation

Storybook is the industry standard:

- One story per variant

- Interactive controls (Args)

- Code snippets

- Accessibility audit (axe addon)

Modern alternatives: Ladle (faster), Histoire (Vue-friendly).

## Testing

- Unit tests for behavior (Vitest, Jest)

- Integration tests (React Testing Library)

- Visual regression (Chromatic, Percy)

- Accessibility (axe-core in CI)

## Versioning

Semver discipline:

- Major: breaking changes

- Minor: additions

- Patch: fixes

Migration guides for every breaking change. Codemods for big migrations (Storybook does this well).

## Distribution

- Internal monorepo package (most common for company-internal libs)

- npm package (public or private registry)

- Tree-shakable bundle

## Common antipatterns

- Building 100 components before 10 are used

- Hard-coded colors in components

- No design tokens; values scattered

- No accessibility

- API that does not allow customization (forced "blessed" patterns)

## Frequently Asked Questions

### Should I build my own library or use Material UI / Chakra?

Use a library if your design is generic. Build your own if you have a distinctive design and a team of 50+ engineers.

### Radix or React Aria?

Radix is the dominant React-only choice in 2026. React Aria has the strongest accessibility but a steeper learning curve.

### How big should our library be?

20–50 components covers most needs. More is over-engineered. Less and engineers feel constrained.
