Token flow

Built a theme-aware token visualizer for my design system case studies, inspired by @ShadcnSpace "Integration Card" 😁 21st.dev/@iamtoribryan/…
Tori Bryan@iamtoribryan
Open the post on X

Token flow shows how a color becomes a design token: the raw value, the palette step that names it, and the role people use in code. Switch the site theme and the values change underneath while the role's name stays put.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primaryPrimary actions, headings
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructiveErrors and irreversible actions
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-borderHairlines and inputs
Token flowThree of fibo's roles, each with what it is for. Switch the site theme to watch them flip.

Examples

Use lines

Rows print what each role is for only when asked. Leave them off for readers who already know the names.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructive
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-border
Without useThe default: three chips per row, nothing underneath.
Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primaryPrimary actions, headings
Single roleOne row on its own, with its use line.

Orientation

The tiers run left to right and stack top to bottom on narrow screens. orientation="vertical" stacks them at every width, for a narrow column or a card.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primaryPrimary actions, headings
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructiveErrors and irreversible actions
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-borderHairlines and inputs
VerticalThe three roles stacked, with their use lines.

Theme

The plate follows the site theme. When it changes, rows with a dark pair scramble to their new values and the swatches fade across, while the role names hold still.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructive
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-border

Theme: light

Theme changeFlips between light and dark every few seconds, so the scramble plays.
Base oklch(0.985 0 0)Primitive neutral-50
Semantic bg-primary
Base oklch(0.704 0.191 22.216)Primitive red-400
Semantic text-destructive
Base oklch(1 0 0 / 10%)Primitive white / 10%
Semantic border-border
Pinned to darkDark values on dark surfaces, whatever the site theme.

Motion

A pulse runs along each wire while the plate is on screen, staggered by row. It stops off screen, even when you pass your own ref, and neither the pulse nor the scramble plays when someone has asked for reduced motion.

In a case study

The lead example: a handful of roles with what each is for, next to the writing that explains them.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primaryPrimary actions, headings
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructiveErrors and irreversible actions
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-borderHairlines and inputs
Three roles with their use lines.

In a themed preview

A preview that owns its own theme can pin the plate to it, so the values match the components beside them.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructive
Switch the preview between light and dark: the buttons and the plate move together.

Anatomy

A dotted plate with a label over each tier, and one row per role below.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
Base oklch(0.922 0 0)Primitive neutral-200
Semantic border-border
  1. Plate
  2. Tiers
  3. Row
The plateTwo roles, each a row of three chips joined by wires.

Each row reads top to bottom on a phone. Every chip carries a swatch of the row's color, and the role can carry a short line on what it is for.

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primaryPrimary actions, headings
  1. Value
  2. Primitive
  3. Swatch
  4. Wire
  5. Role
  6. Use
A rowOne role, stacked the way it lays out on narrow screens.

Guidelines

  • 01Use it in docs, case studies and onboarding, where the point is how a token is built, not what it looks like.
  • 02Keep it to three to five rows, one per role.
  • 03Pick roles that change between themes to show why roles exist: the name stays put while the color underneath moves.
  • 04Show the use lines when readers don't know the role names yet.

Best practices

Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
DoName the role the way people write it in code.
Base oklch(0.205 0 0)Primitive neutral-900
Semantic dark gray
Don'tDon't describe the color in the last column. That's what the swatch is for.
Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-primary
Base oklch(0.505 0.213 27.518)Primitive red-700
Semantic text-destructive
DoChart roles, each with its own job.
Base oklch(0.922 0 0)Primitive neutral-200
Semantic bg-neutral-200
Base oklch(0.205 0 0)Primitive neutral-900
Semantic bg-neutral-900
Don'tDon't chart palette steps as if they were roles. The last column only repeats the middle one.

Accessibility

  • 01Every chip says which tier it belongs to, so a screen reader hears "Primitive, neutral-900" rather than a bare value.
  • 02The scramble is hidden from assistive technology. Only the settled value is read out.
  • 03The pulse only runs while the plate is on screen, and neither the pulse nor the scramble plays when someone has asked for reduced motion.

References