๐ŸŽฏ How Tokens Work

Aural UI uses a two-layer token system:

Layer 1: Primitive Tokens (Foundation)

These are the actual color values that never change across themes:

:root {
  /* Color scales: 50 (lightest) โ†’ 950 (darkest) */
  --primary-400: #5ebd8f;     /* Vibrant green */
  --secondary-500: #06b6d4;    /* Cyan */
  --neutral-100: #f5f5f5;      /* Light gray */
  --neutral-900: #171717;      /* Dark gray */
}

Layer 2: Semantic Tokens (Meaning)

These tokens map to purposes and change per theme:

/* Dark Theme */
:root {
  --color-bg-primary: #0f0f1a;      /* Dark background */
  --color-text-primary: #f5f5fa;     /* Light text */
}

/* Light Theme */
:root {
  --color-bg-primary: #ffffff;       /* Light background */
  --color-text-primary: #111827;     /* Dark text */
}

Same token name, different values per theme!

Layer 3: Components Use Semantic Tokens

.btn-primary {
  background: var(--color-button-primary-bg);
  color: var(--color-button-primary-text);
}

.card {
  background: var(--color-card-bg);
  border: 1px solid var(--color-border-subtle);
}

โœ… What Tokens Can Control

Tokens control ~95% of visual styling - any CSS value, but not CSS structure.

Property Type Support Example
Colors โœ… Full --color-primary: #5ebd8f
Spacing โœ… Full --space-4: 1rem
Typography โœ… Full --text-lg: 1.125rem
Border Radius โœ… Full --radius-md: 0.75rem
Shadows โœ… Full --shadow-lg: 0 20px 25px...
Transitions โœ… Full --duration-fast: 150ms
Gradients โœ… Full --gradient: linear-gradient(...)
Property Names โŒ No Can't tokenize property names
Selectors โŒ No Can't tokenize CSS selectors
Media Queries โš ๏ธ Limited Can't use directly in @media

๐Ÿ“š Token Categories

Colors

Color scales from 50 (lightest) to 950 (darkest). Each scale provides semantic meaning and maintains WCAG AA contrast standards.

Primary Colors

Token Usage
--primary-50 Lightest shade
--primary-100 Very light shade
--primary-500 Main brand color
--primary-700 Dark shade
--primary-900 Darkest shade

Semantic Colors

Token Usage
--color-success Success states and positive actions
--color-error Error states and destructive actions
--color-warning Warning states and caution
--color-info Informational states

Text Colors

Token Usage
--color-text-primary Main text color
--color-text-secondary Secondary text, less prominent
--color-text-tertiary Tertiary text, least prominent

Spacing

Spacing scale based on a 4px (0.25rem) unit for consistent layouts. Use these tokens for margin, padding, and gap properties.

Token Value Pixels
--space-1 0.25rem 4px
--space-2 0.5rem 8px
--space-3 0.75rem 12px
--space-4 1rem 16px
--space-6 1.5rem 24px
--space-8 2rem 32px
--space-12 3rem 48px
--space-16 4rem 64px

Usage Example:

padding: var(--space-4);
margin-top: var(--space-6);

Size

--size-N sizes a UI element's own box โ€” icon dimensions, avatar diameter, status-dot size, toggle track/thumb โ€” as opposed to --space-N, which sizes the gap between elements (see the Spacing section above).

โš ๏ธ Not the same convention as --space-N
--size-N's N is the literal pixel value โ€” --size-14 is 14px, --size-44 is 44px. --space-N uses N = px รท 4, so --space-14 is 56px. The same number means two different things in the two scales โ€” never assume --size-N and --space-N with the same N are interchangeable. Always check the actual value in the table below rather than inferring it from the name.

Where a size value coincides with an existing --space-N value, --size-N aliases it instead of duplicating the literal (e.g. --size-16: var(--space-4)), so the two scales stay numerically consistent even though their naming conventions differ.

Size Scale

Boxes below are rendered at their real token size, smallest to largest.

--size-6
--size-14
--size-18
--size-24
--size-36
--size-44
Token Value Pixels
--size-6 0.375rem 6px
--size-12 var(--space-3) 12px
--size-14 0.875rem 14px
--size-16 var(--space-4) 16px
--size-18 1.125rem 18px
--size-20 var(--space-5) 20px
--size-24 var(--space-6) 24px
--size-28 var(--space-7) 28px
--size-32 var(--space-8) 32px
--size-36 2.25rem 36px
--size-40 var(--space-10) 40px
--size-44 2.75rem 44px
--size-48 var(--space-12) 48px
--size-52 3.25rem 52px
--size-56 var(--space-14) 56px
--size-64 var(--space-16) 64px
--size-80 var(--space-20) 80px
--size-96 var(--space-24) 96px

Container / Overlay Width Scale

Larger steps for dialog, drawer, and overlay max-width โ€” same literal-pixel convention as the icon/control scale above, just bigger numbers.

Token Value Pixels
--size-360 22.5rem 360px
--size-480 30rem 480px
--size-640 40rem 640px
--size-800 50rem 800px

Usage

.icon-sm {
  width: var(--size-14);
  height: var(--size-14);
} /* 14px small icon */

.avatar {
  width: var(--size-40);
  height: var(--size-40);
} /* 40px avatar */

.toggle-track {
  width: var(--size-44);
  height: var(--size-24);
} /* 44px touch target */

.dialog {
  max-width: var(--size-480);
} /* 480px dialog */

Do / Don't

/* Don't โ€” raw px for a control dimension */
.status-dot {
  width: 6px;
  height: 6px;
}

/* Don't โ€” reaching for the wrong scale by number-matching intuition */
.icon-md {
  width: var(--space-14);
} /* this is 56px, not 14px! */

/* Do */
.status-dot {
  width: var(--size-6);
  height: var(--size-6);
}
.icon-md {
  width: var(--size-18);
}

Typography

Typography tokens for font sizes, weights, line heights, and letter spacing. All sizes are responsive and accessible.

Font Sizes

Token Value Pixels
--text-xs 0.75rem 12px
--text-sm 0.875rem 14px
--text-base 1rem 16px
--text-lg 1.125rem 18px
--text-xl 1.25rem 20px
--text-2xl 1.5rem 24px
--text-3xl 1.875rem 30px
--text-4xl 2.25rem 36px

Font Weights

Token Value
--font-light 300
--font-normal 400
--font-medium 500
--font-semibold 600
--font-bold 700
--font-extrabold 800

Border Radius

Border radius tokens for consistent component rounding. From sharp corners to fully circular elements.

Token Value Usage
--radius-none 0 No rounding
--radius-sm 0.25rem Subtle rounding
--radius 0.5rem Default rounding
--radius-md 0.75rem Medium rounding
--radius-lg 1rem Large rounding
--radius-xl 1.25rem Extra large rounding
--radius-2xl 1.5rem Very large rounding
--radius-full 9999px Fully circular/pill shape

Shadows & Elevation

Shadow tokens provide depth and elevation. Use these to create visual hierarchy in your interfaces.

Standard Shadows

Token Usage
--shadow-xs Extra subtle shadow
--shadow-sm Small shadow
--shadow Default shadow
--shadow-md Medium shadow
--shadow-lg Large shadow
--shadow-xl Extra large shadow

Colored Shadows

Token Usage
--shadow-primary Primary color shadow
--shadow-success Success color shadow
--shadow-warning Warning color shadow
--shadow-error Error color shadow

Z-Index

Two layers, same pattern as color: a core scale of raw, meaningless rungs (--z-0 through --z-90), and a semantic scale of intent-named aliases onto those rungs (--z-dropdown, --z-modal, --z-popover, and so on). The jumps between rungs are deliberately uneven โ€” they were set to match stacking values already in use across components (dropdowns at 1000, overlays near 9999, etc.), so introducing the token scale didn't change any existing stacking behavior.

Stacking Order

Each panel below is rendered at its real semantic z-index, so you can see what sits above what.

sticky navbar --z-sticky (100)
dropdown panel --z-dropdown (1000)
modal --z-modal (2000)
drawer overlay --z-overlay (9998)
tooltip / toast --z-popover (9999)
command palette --z-max (10000)

Core Scale

Token Value
--z-0 0
--z-10 10
--z-20 20
--z-30 30
--z-40 100
--z-50 1000
--z-60 2000
--z-70 9998
--z-80 9999
--z-90 10000

Semantic Scale

Token Resolves to Use for
--z-sticky var(--z-40) ยท 100 Sticky in-flow elements, e.g. a sticky navbar
--z-dropdown var(--z-50) ยท 1000 Floating panels anchored to a trigger: dropdown, select, combobox, date/time pickers, suggestions
--z-modal var(--z-60) ยท 2000 App-level modal backdrop + content
--z-overlay var(--z-70) ยท 9998 A secondary overlay above a modal, e.g. a drawer backdrop
--z-popover var(--z-80) ยท 9999 Content that must float above everything in normal flow
--z-tooltip var(--z-80) ยท 9999 Same layer as popover โ€” tooltips
--z-toast var(--z-80) ยท 9999 Same layer as popover โ€” toast notifications
--z-max var(--z-90) ยท 10000 Absolute top layer: command palette, snackbar, lightbox, submenus

When to Use It โ€” and When Not To

Component code should reference the semantic tokens (var(--z-dropdown)), not the raw --z-N rungs, so the meaning of a layer is visible at the call site.

Small z-index values used purely for local stacking tricks inside a single component are not part of this scale and don't need a token. If you're layering a decorative pseudo-element above its own container, ordering a badge dot over an avatar, or doing any z-index trick where everything being stacked lives inside one component's own DOM subtree โ€” and the value is 20 or smaller โ€” leave it as a plain integer. These values never interact with another component's stacking context, so giving them a global name would be noise, not clarity. Reach for a global token only when the element needs to stack above or below content belonging to a different component.

/* Local stacking trick โ€” stays a plain small integer, no token needed */
.avatar-status-dot {
  position: absolute;
  z-index: 1;
}

/* Cross-component global layer โ€” use the semantic token */
.dropdown-menu {
  position: absolute;
  z-index: var(--z-dropdown);
}
.modal-backdrop {
  position: fixed;
  z-index: var(--z-modal);
}

Do / Don't

/* Don't โ€” raw global-scale number, meaning not visible at the call site */
.toast {
  z-index: 9999;
}

/* Don't โ€” reaching past the semantic layer for no reason */
.toast {
  z-index: var(--z-80);
}

/* Do */
.toast {
  z-index: var(--z-toast);
}

โšก Animation & Transitions

Motion tokens give every animated component a consistent timing vocabulary. There are three layers: durations (how long), easing functions (the acceleration curve), and composite transitions (ready-to-use shorthands). All are available as Figma Variables in the Aural/Animation collection.

Duration Scale

Six steps from instant to one second. Click โ–ถ on any row to preview it.

--duration-instant
0ms
Toggles, focus rings โ€” no visible motion
--duration-fast
150ms
Hover, button press, micro-interactions
--duration-normal
300ms
Menus, tooltips, modals appearing
--duration-slow
500ms
Drawers, page transitions
--duration-slower
750ms
Emphasis, onboarding moments
--duration-slowest
1000ms
Skeleton loaders, looping animations

Easing Functions

Six named curves. Click โ–ถ to see each one animate โ€” notice how acceleration differs.

--ease-linear
Spinners, looping, progress bars
--ease-in
Elements leaving the screen
--ease-out
Elements entering the screen
--ease-in-out
Default โ€” most UI interactions
--ease-bounce
Playful confirmations, emphasis
--ease-spring
Modals, drawers, natural snap

Composite Transitions

Pre-built shorthands combining duration + easing. Use these to keep motion consistent across components without repeating yourself.

Token Value Best for
--transition-fast 150ms ease-in-out Generic fast shorthand
--transition-normal 300ms ease-in-out Generic normal shorthand
--transition-slow 500ms ease-in-out Generic slow shorthand
--transition-all-fast all 150ms ease-in-out All properties, fast โ€” most buttons/links
--transition-all-normal all 300ms ease-in-out All properties, standard speed
--transition-colors color, bg, border 150ms Color-only โ€” no layout shift
--transition-transform transform 150ms ease-in-out GPU-composited โ€” smooth on mobile
--transition-opacity opacity 300ms ease-in-out GPU-composited โ€” fades and overlays

Usage

/* Use a composite token for the common case */
.btn {
  transition: var(--transition-all-fast);
}

/* Compose duration + easing yourself for precise control */
.drawer {
  transition: transform var(--duration-slow) var(--ease-spring);
}

/* Prefer GPU-composited props for performance */
.modal-overlay {
  transition: var(--transition-opacity);
}
๐Ÿ“ Figma Variables
Duration tokens are FLOAT variables and easing tokens are STRING variables in the Aural/Animation collection. Composite transitions are not Figma Variables โ€” they're CSS-only shorthands. Figma does not yet support binding animation variables to layer properties directly, but they serve as accurate handoff spec values.

Using Design Tokens

Design tokens can be used in your CSS to ensure consistency with the Aural UI design system.

In Your CSS

.my-component {
  color: var(--color-text-primary);
  background: var(--color-bg-secondary);
  padding: var(--space-4);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-base);
}

Customizing Tokens

You can override any token to customize the design system:

:root {
  --color-primary: #8B5CF6;
  --radius-md: 1rem;
  --space-4: 1.25rem;
}

๐ŸŽจ Creating Custom Themes

Method 1: Override Individual Tokens

Create a simple style block to customize specific aspects:

<style>
  :root {
    /* Change primary brand color */
    --color-primary: #8B5CF6;     /* Purple */

    /* Adjust spacing scale */
    --space-4: 1.25rem;           /* Increase base spacing */

    /* Rounder corners */
    --radius-md: 1rem;            /* More rounded */
  }
</style>

Method 2: Create a Full Custom Theme

Build a complete theme file matching your brand:

/* my-brand.css */
:root {
  /* Brand Colors */
  --color-primary: #8B5CF6;
  --color-secondary: #EC4899;

  /* Backgrounds (Dark Theme) */
  --color-bg-primary: #1a1a1a;
  --color-bg-secondary: #2a2a2a;
  --color-bg-tertiary: #3a3a3a;

  /* Text */
  --color-text-primary: #ffffff;
  --color-text-secondary: #a0a0a0;

  /* Borders */
  --color-border-subtle: rgba(255, 255, 255, 0.1);

  /* Typography */
  --font-sans: "Inter", system-ui, sans-serif;

  /* Spacing - Compact Scale */
  --space-4: 0.875rem;
  --space-6: 1.25rem;
}

Load it:

<link rel="stylesheet" href="aural-ui.css">
<link rel="stylesheet" href="my-brand.css">

๐Ÿ”ง Advanced Techniques

Token Composition

Combine tokens to create new values:

:root {
  --duration-fast: 150ms;
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* Compose them */
  --transition-fast: var(--duration-fast) var(--ease-in-out);
}

Math with Tokens

Use calc() for dynamic values:

.double-padding {
  padding: calc(var(--space-4) * 2);  /* 2rem */
}

.half-margin {
  margin: calc(var(--space-4) / 2);   /* 0.5rem */
}

Fallback Values

Provide defaults for missing tokens:

.card {
  /* If --radius-md doesn't exist, use 0.75rem */
  border-radius: var(--radius-md, 0.75rem);
}

๐Ÿ’ก Best Practices

  1. Use semantic tokens in components - Reference --color-bg-primary, not --neutral-900
  2. Don't hardcode values - Always use tokens for consistency
  3. Test in multiple themes - Switch themes to ensure proper contrast
  4. Override sparingly - Only customize what you need
  5. Document custom tokens - Comment your customizations
๐Ÿ’ก Pro Tip:

Use the theme switcher (top right) to see how tokens adapt across all 9 themes instantly!