Architecture
How Toucan splits tokens, styles, interactions, React primitives, patterns, and the CLI without duplicating ownership.
Package Roles
Toucan is a modular React design system built from small first-party packages. Each package owns one layer of the system, and higher layers depend on lower layers instead of copying source.
Tokens
@toucan-ui/tokens ships the default design-token preset and importable foundation CSS. Custom themes use the same raw, alias, system, and dark token tiers.
Styles
@toucan-ui/styles owns framework-agnostic .tcn-* component CSS, utility CSS, responsive templates, and the style manifest used by the CLI.
React
@toucan-ui/react owns accessible React primitives, React adapters, hooks, and the React ejection manifest. Component entries import their shared CSS.
Interactions
@toucan-ui/interactions owns framework-neutral reducers, machines, and DOM helpers for keyboard navigation, focus, disclosure, listbox, menu, and related behavior.
Types
@toucan-ui/types owns framework-neutral type vocabulary. React-specific prop types stay in @toucan-ui/react.
Patterns + CLI
@toucan-ui/patterns composes React primitives into larger UI sections. @toucan-ui/cli builds token CSS, runs diagnostics/init, and ejects local component source.
The Token Cascade
Tokens flow through three tiers with strict referencing direction: raw -> alias -> system. Each tier adds semantic meaning.
Raw Tokens
Primitive values with no semantic meaning. Colour scales, sizing steps, font stacks, shadows, opacity, and layout scales live here.
{
"color": {
"blue": {
"500": { "$value": "#3b82f6", "$type": "color" },
"600": { "$value": "#2563eb", "$type": "color" }
},
"neutral": {
"0": { "$value": "#ffffff", "$type": "color" },
"900": { "$value": "#171717", "$type": "color" }
}
}
}Alias Tokens
Semantic roles that reference raw values. The default preset provides neutral, functional aliases; branded themes override these slots to express a different visual identity.
{
"color": {
"primary": { "$value": "{color.neutral.900}", "$type": "color" },
"on-primary": { "$value": "{color.white}", "$type": "color" },
"surface": {
"default": { "$value": "{color.neutral.0}", "$type": "color" }
}
}
}System Tokens
Component-specific tokens that reference aliases. System tokens handle structural properties such as sizing, spacing, radius, and font weight. Colour CSS usually references alias tokens directly so theme changes cascade without extra indirection.
{
"button": {
"radius": { "$value": "{radius.md}", "$type": "dimension" },
"font-weight": { "$value": "{font.weight.medium}", "$type": "fontWeight" },
"md": {
"padding-x": { "$value": "{spacing.lg}", "$type": "dimension" },
"height": { "$value": "{sizing.lg}", "$type": "dimension" }
}
}
}Default CSS Path
For package-import usage, import the default foundation tokens once in your global CSS. Add the shared responsive rules when using responsive Grid or Flex props. Component CSS is imported by the React component entries you use.
@import '@toucan-ui/tokens/default.css';
@import '@toucan-ui/styles/responsive/default.css';// react/src/components/button/index.ts
import '@toucan-ui/styles/components/button/button.css';
export { Button } from './button';CLI CSS Path
The CLI compiles custom token sets into a local toucan.css. That file contains foundation tokens, selected component CSS, utility CSS, and responsive rules from the same source packages.
npm install -D @toucan-ui/cli
npx toucan build --tokens ./my-tokens --out ./css/toucan/* Custom theme import — compiled by `npx toucan build` */
@import './css/toucan/toucan.css';Use --components button,input,select to build a smaller CSS file for a known component set. Without --components, the CLI includes the complete component CSS surface.
Full-Ownership Ejection
Package imports are the normal path. When you want local ownership, toucan eject <component> copies canonical React source plus the minimal local dependency closure into your app.
npx toucan eject button
npx toucan eject select --out ./src/components --forceEjected components do not import from @toucan-ui/react. Shared vendored dependencies live under _toucan, component CSS is copied next to the component, and app-level token CSS is still required once.
Component Contract Model
React primitives emit semantic HTML, ARIA attributes, data-* state hooks, and .tcn-* class names. Shared component CSS maps those hooks to token values.
<button
class="tcn-button"
data-variant="primary"
data-size="md"
aria-busy="false"
>
Click me
</button>.tcn-button[data-variant="primary"] {
background-color: var(--color-primary);
color: var(--color-on-primary);
}
.tcn-button[data-size="md"] {
height: var(--button-md-height);
padding: var(--button-md-padding-y) var(--button-md-padding-x);
}Interaction Ownership
Interaction logic is not a theme or animation layer. The @toucan-ui/interactions package owns reusable behavior primitives: reducers, state machines, keyboard navigation, focus management, dismissal, and DOM helpers. React adapters in @toucan-ui/react wrap those primitives for React components.
This keeps behavior testable outside React while letting the React package own the public component API.
Monorepo Structure
packages/
tokens/ -> default token presets + foundation CSS
styles/ -> framework-agnostic component CSS + responsive templates
types/ -> framework-neutral type vocabulary
interactions/ -> framework-neutral behavior primitives + DOM helpers
react/ -> React primitives, hooks, adapters, ejection manifest
patterns/ -> 36 React patterns composed from primitives
cli/ -> toucan build/init/info/doctor/eject
apps/
docs/ -> documentation site + Wiz'rd theme configuratorBuild order follows ownership: tokens and styles feed the CLI; interactions and types feed React; React feeds patterns and the docs app.