Skip to Content
Docs

Design tokens

Every colour, type, space, corner, shadow and motion token a page uses.

View as Markdown

The tokens of the design system, as Tailwind utilities. A page gets them from the theme, once in its CSS: @import "@0x1audio/design-system/theme.css". A custom page shows the setup.

Colour

Use these as Tailwind utilities (bg-card, text-muted-foreground, border-border). They follow light and dark on their own.

NeedUseNot
The pagebg-background
A raised surface: a card, a group of settingsbg-card with border-bordera shadow at rest
Something floating: a menu, a dialog, a toastbg-popover with shadow-lg (the components do this)
Texttext-foreground; text-muted-foreground for secondary text; text-subtle-foreground for hints, counts and column headersa grey below 4.5:1 contrast for anything people must read
Linesborder-border, a hairline; border-border-strong for outline buttons and chipsa border where space already separates
Hover, pressed, selectedbg-hover, bg-pressed, bg-selecteda different colour for each state
Fieldsbg-field, hover:bg-field-hover
Statustext-destructive, text-success, text-warning-foregroundstatus colours as decoration
Focusthe ring every component shows on :focus-visibleremoving outlines; a coloured ring
A waveform's resting barsbg-wave or fill-wave; the part already played is ink (text-foreground)a grey from the text scale; colour in a waveform
Behind a dialogbg-scrim
Your accentaccent in app.json, and <AppHero accent="#20b4c4" />your accent on buttons, text or backgrounds below the hero

Tints are derived, not new colours. A status wash is the status token at a fixed opacity: bg-success/8, bg-warning/8 and bg-destructive/6 for fills, border-success/25 and the like for lines. Callout with a tone does this for you.

bg-chrome and lit belong to Mixel's own window frame and its live indicators, so apps don't use them.

Type

Figtree, included with the theme. Seven sizes, each with its own line height and tracking:

TokenSize / lineUse
text-display32 / 36One hero line, and rarely in an app
text-title22 / 28The page title (PageHeader, AppHero)
text-heading15 / 22Section titles, dialog titles, empty-state titles
text-body14 / 20Rows, buttons, paragraphs
text-small13 / 18Secondary text, menu items, labels, facts lines
text-caption12 / 16Meta lines and counts
text-micro11 / 14Column headers, menu labels, shortcuts
  • Weights: 400 for body text, 500 for labels and row titles, 600 for headings.
  • Numbers that change or line up get tabular-nums: lengths, BPM, counts, percentages.
  • Sentence case everywhere, and no all-caps labels.
  • Tailwind's own sizes (text-sm, text-lg) and fixed sizes like text-[13px] are off the scale.

Space

A 4 px grid, which is Tailwind's spacing scale. The rhythm that repeats:

  • The page: px-8 at the sides. PageHeader brings its own space above and below; a PageSection is py-4, with gap-2 between its title and its content.
  • Rows: 40 px (min-h-10) for a list of sounds or files, gap-px apart. Hover fills separate rows, not dividers.
  • Toolbars: every control h-8, with gap-2 between them.

Shared widths and grids are tokens, not fixed values: max-w-dialog, max-w-settings, max-w-page, and grid-cols-(--grid-tiles), grid-cols-(--grid-cards), grid-cols-(--grid-label-value). Never w-[26rem].

Corners

Crisp corners, to sit with Mixel's pixel mark.

TokenSizeUse
rounded-sm4 pxKbd, tiny chips
rounded-md6 pxRows, small buttons, menu items
rounded-lg8 pxButtons, fields, tiles, toolbar controls
rounded-xl12 pxCards, dialogs, popovers, the hero
rounded-fullRound play buttons, avatars, switches
rounded-icon22%App icons only

Never more than rounded-xl on a container.

Elevation

TokenUse
noneEverything at rest on the page. A hairline border is enough.
shadow-xsFilled buttons, app icons
shadow-smThe active tab of a segmented control; a card lifting on hover, one step only
shadow-mdA popover close to what opened it
shadow-lgMenus, dialogs, toasts

No coloured shadows, no glows, and no blur as decoration.

Motion

TokenValueUse
--duration-fast120 msColour, background, border and press. Built into every component.
--duration180 msEntering, cross-fades, menus opening
--duration-slow280 msDialogs, progress bars, larger moves
--ease-outEverything entering or responding
--ease-in-outSomething moving between two places
--ease-springA dialog scaling in, once
  • New content enters with animate-enter. A list cascades with stagger on the list and style={{ "--i": index }} on each item.
  • Buttons press to active:scale-98. Nothing grows on hover.
  • Menus and dialogs open from what opened them, and close faster than they open. The components do this.
  • Only live work loops: an indeterminate Progress, a Skeleton. Nothing loops for decoration.
  • Reduced motion is handled by the theme.

On this page