Design tokens are the atomic values that define Voidable’s visual language. Every color, spacing step, font size, shadow, radius, and motion curve is expressed as a CSS custom property prefixed with --void-. Components consume these tokens rather than hard-coding values, so a single override propagates everywhere.
Tokens ship in the @voidable/theme package. After importing it, all tokens are available as standard CSS custom properties:
@import ' @voidable/theme ' ;
The theme is organized into two tiers:
Primitives (primitives.css) — Raw scales with no semantic meaning. Color palettes, spacing steps, font stacks.
Semantic tokens (tokens.css) — Purpose-driven aliases like --void-color-bg and --void-color-text that reference primitives and adapt based on the active theme.
Primitive color palettes are always available on :root regardless of the active theme. They exist so semantic tokens (and your own overrides) can reference them.
Token Value --void-stone-50#fafaf9--void-stone-100#f5f5f4--void-stone-200#e7e5e4--void-stone-300#d6d3d1--void-stone-400#a8a29e--void-stone-450#908a85--void-stone-500#78716c--void-stone-600#57534e--void-stone-700#44403c--void-stone-800#292524--void-stone-900#1c1917--void-stone-950#0c0a09
Token Value --void-red-50#fef2f2--void-red-100#fee2e2--void-red-200#fecaca--void-red-300#fca5a5--void-red-400#f87171--void-red-500#ef4444--void-red-600#dc2626--void-red-700#b91c1c--void-red-800#991b1b--void-red-900#7f1d1d--void-red-950#450a0a
Token Value --void-amber-50#fefae4--void-amber-100#fdf1be--void-amber-200#f9e182--void-amber-300#f1cb48--void-amber-400#e5c03c--void-amber-500#cca93c--void-amber-600#a88a2a--void-amber-700#846b20--void-amber-800#655118--void-amber-900#503f13--void-amber-950#30260b
Token Value --void-green-50#f0fdf4--void-green-100#dcfce7--void-green-200#bbf7d0--void-green-300#86efac--void-green-400#4ade80--void-green-500#22c55e--void-green-600#16a34a--void-green-700#15803d--void-green-800#166534--void-green-900#14532d--void-green-950#052e16
Token Value --void-blue-50#eff6ff--void-blue-100#dbeafe--void-blue-200#bfdbfe--void-blue-300#93c5fd--void-blue-400#60a5fa--void-blue-500#3b82f6--void-blue-600#2563eb--void-blue-700#1d4ed8--void-blue-800#1e40af--void-blue-900#1e3a8a--void-blue-950#172554
Token Value --void-purple-50#faf5ff--void-purple-100#f3e8ff--void-purple-200#e9d5ff--void-purple-300#d8b4fe--void-purple-400#c084fc--void-purple-500#a855f7--void-purple-600#9333ea--void-purple-700#7e22ce--void-purple-800#6b21a8--void-purple-900#581c87--void-purple-950#3b0764
Token Value --void-pink-50#fdf2f8--void-pink-100#fce7f3--void-pink-200#fbcfe8--void-pink-300#f9a8d4--void-pink-400#f472b6--void-pink-500#ec4899--void-pink-600#db2777--void-pink-700#be185d--void-pink-800#9d174d--void-pink-900#831843--void-pink-950#500724
Token Value Purpose --void-black#000000Pure black --void-white#ffffffPure white --void-dark-1#0a0a0aDark surface step 1 (near-black elevation) --void-dark-2#0b0b0bDark surface step 2 --void-dark-3#111111Dark surface step 3 --void-dark-4#141414Dark surface step 4
Semantic tokens carry purpose — “the background color” rather than “stone-900”. They change automatically between dark and light themes via the data-theme attribute on your root element.
Dark mode is the default . Set data-theme="light" on <html> to activate light mode.
Token Dark value Light value --void-color-bgvar(--void-black)var(--void-white)--void-color-bg-secondaryvar(--void-dark-1)var(--void-stone-100)--void-color-bg-elevatedvar(--void-dark-3)var(--void-white)--void-color-bg-hovervar(--void-dark-4)var(--void-stone-200)--void-color-bg-accentvar(--void-dark-2)var(--void-stone-100)--void-color-bg-overlayblack 70% / transparentblack 30% / transparent
Token Dark value Light value --void-color-textvar(--void-stone-100)var(--void-stone-900)--void-color-text-secondaryvar(--void-stone-400)var(--void-stone-600)--void-color-text-mutedvar(--void-stone-500)var(--void-stone-500)--void-color-text-tertiaryvar(--void-stone-450)var(--void-stone-400)--void-color-text-disabledvar(--void-stone-600)var(--void-stone-300)--void-color-text-on-accentvar(--void-black)var(--void-white)
Token Dark value Light value --void-color-borderwhite 14% / transparentvar(--void-stone-300)--void-color-border-strongwhite 22% / transparentvar(--void-stone-400)--void-color-border-focuswhite 55% / transparentvar(--void-stone-600)
Token Dark value Light value --void-color-accentvar(--void-white)var(--void-stone-900)--void-color-accent-hovervar(--void-stone-200)var(--void-stone-950)
Status tokens map to the primitive palettes. Dark mode uses the -500 stop; light mode uses -600 for better contrast on white backgrounds.
Token Dark value Light value --void-color-errorvar(--void-red-500)var(--void-red-600)--void-color-warningvar(--void-amber-500)var(--void-amber-600)--void-color-successvar(--void-green-500)var(--void-green-600)--void-color-infovar(--void-blue-500)var(--void-blue-600)--void-color-noticevar(--void-purple-500)var(--void-purple-600)--void-color-highlightvar(--void-pink-500)var(--void-pink-600)
Subtle status colors use color-mix() to create low-opacity tinted backgrounds. Dark mode uses 14% opacity; light mode uses 8%.
Token Dark value Light value --void-color-error-subtleerror 14% / transparenterror 8% / transparent--void-color-warning-subtlewarning 14% / transparentwarning 8% / transparent--void-color-success-subtlesuccess 14% / transparentsuccess 8% / transparent--void-color-info-subtleinfo 14% / transparentinfo 8% / transparent--void-color-notice-subtlenotice 14% / transparentnotice 8% / transparent--void-color-highlight-subtlehighlight 14% / transparenthighlight 8% / transparent
Spacing tokens use a numeric scale based on a 0.25rem (4px) grid. Named aliases provide T-shirt sizing for common use.
Token Value --void-space-10.25rem (4px)--void-space-1h0.375rem (6px)--void-space-20.5rem (8px)--void-space-2h0.625rem (10px)--void-space-30.75rem (12px)--void-space-41rem (16px)--void-space-51.25rem (20px)--void-space-61.5rem (24px)--void-space-71.75rem (28px)--void-space-82rem (32px)--void-space-92.25rem (36px)--void-space-102.5rem (40px)--void-space-123rem (48px)--void-space-143.5rem (56px)--void-space-153.75rem (60px)--void-space-164rem (64px)--void-space-205rem (80px)--void-space-246rem (96px)--void-space-287rem (112px)--void-space-307.5rem (120px)--void-space-328rem (128px)--void-space-358.75rem (140px)--void-space-4010rem (160px)
Token Maps to --void-space-xs--void-space-1 (0.25rem)--void-space-sm--void-space-2 (0.5rem)--void-space-md--void-space-3 (0.75rem)--void-space-lg--void-space-4 (1rem)--void-space-xl--void-space-6 (1.5rem)
Defined in tokens.css, these mirror the named spacing primitives:
Token Maps to --void-spacing-xsvar(--void-space-xs)--void-spacing-smvar(--void-space-sm)--void-spacing-mdvar(--void-space-md)--void-spacing-lgvar(--void-space-lg)--void-spacing-xlvar(--void-space-xl)
Token Value --void-text-2xs0.625rem (10px)--void-text-xs0.75rem (12px)--void-text-sm0.8125rem (13px)--void-text-base0.875rem (14px)--void-text-md1rem (16px)--void-text-lg1.125rem (18px)--void-text-xl1.25rem (20px)--void-text-2xl1.5rem (24px)--void-text-3xl1.875rem (30px)--void-text-4xl2.25rem (36px)--void-text-5xl3rem (48px)
Token Value --void-weight-normal400--void-weight-medium500--void-weight-semibold600--void-weight-bold700
Token Value Notes --void-leading-display0.92Large display headings --void-leading-none1No extra leading --void-leading-snug1.05Slightly more than none --void-leading-tight1.2--void-leading-normal1.5--void-leading-relaxed1.7--void-leading-loose1.75Extra loose for code blocks
Token Value Use case --void-tracking-tightest-0.05emDisplay text, wordmarks --void-tracking-tighter-0.04emLarge headings --void-tracking-tight-0.025emHeadings --void-tracking-snug-0.01emSubheadings, card titles --void-tracking-normal0emBody text (default) --void-tracking-wide0.04emTags, badges --void-tracking-wider0.06emLabels --void-tracking-widest0.1emUppercase labels, section headers
Token Value --void-font-sans'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif--void-font-mono'JetBrains Mono', ui-monospace, 'SF Mono', 'Fira Code', monospace
Token Value --void-radius-none0--void-radius-xs4px--void-radius-sm6px--void-radius-md8px--void-radius-lg12px--void-radius-xl16px--void-radius-full9999px
The data-shape="sharp" attribute on a parent element resets all radius tokens to 0, giving every component a sharp-cornered appearance:
< html data-shape = " sharp " >
Shadows use white-based rgba values for glow-style elevation on dark surfaces.
Token Value --void-shadow-sm0 1px 3px rgba(255,255,255,.14)--void-shadow-md0 2px 6px rgba(255,255,255,.12), 0 10px 24px rgba(255,255,255,.20)--void-shadow-lg0 4px 10px rgba(255,255,255,.16), 0 22px 50px rgba(255,255,255,.28)--void-shadow-xl0 6px 14px rgba(255,255,255,.20), 0 40px 88px rgba(255,255,255,.38)
Subtle 1px ring effects for card edges and elevated surfaces:
Token Value --void-ring-hair0 0 0 1px rgba(255,255,255,.06)--void-ring-hair-strong0 0 0 1px rgba(255,255,255,.12)
Token Value --void-duration-fast100ms--void-duration-normal200ms--void-duration-slow300ms
Token Value --void-ease-incubic-bezier(0.4, 0, 1, 0.2)--void-ease-outcubic-bezier(0, 0, 0.2, 1)--void-ease-in-outcubic-bezier(0.4, 0, 0.2, 1)
A fixed stacking order so overlapping elements layer predictably:
Token Value --void-z-dropdown100--void-z-sticky200--void-z-modal300--void-z-toast400--void-z-tooltip500
Token Value --void-icon-stroke-width1.5
Token Value --void-sidebar-width15rem--void-sidebar-collapsed-width3.75rem
Many Voidable components use an internal --tone custom property pattern for color theming. Instead of writing separate rulesets for every color variant, each component defines:
--tone : var ( --void-color-accent );
void-badge [ color = " error " ] { --tone : var ( --void-color-error ); }
void-badge [ color = " warning " ] { --tone : var ( --void-color-warning ); }
void-badge [ color = " success " ] { --tone : var ( --void-color-success ); }
Some components derive additional tones for subtle backgrounds and borders:
--tone : var ( --void-color-accent );
--tone-subtle : color-mix ( in srgb , var ( --tone ) 14 % , transparent );
--tone-border : color-mix ( in srgb , var ( --tone ) 36 % , transparent );
background : var ( --tone-subtle );
border : 1 px solid var ( --tone-border );
You set the tone from HTML using the color attribute:
< void-badge color = " error " > 3 </ void-badge >
< void-stat color = " success " > +12% </ void-stat >
The available color values are: error, warning, success, info, notice, and highlight. The default (no attribute) uses --void-color-accent.
Reference any token as a standard CSS custom property:
background : var ( --void-color-bg-elevated );
border : 1 px solid var ( --void-color-border );
border-radius : var ( --void-radius-md );
padding : var ( --void-space-4 );
font-family : var ( --void-font-sans );
font-size : var ( --void-text-sm );
color : var ( --void-color-text );
box-shadow : var ( --void-shadow-md );
transition : background var ( --void-duration-normal ) var ( --void-ease-out );
background : var ( --void-color-bg-hover );
Tokens compose naturally. Build a status banner using semantic colors:
padding : var ( --void-space-3 ) var ( --void-space-4 );
border-radius : var ( --void-radius-sm );
font-size : var ( --void-text-sm );
font-weight : var ( --void-weight-medium );
line-height : var ( --void-leading-normal );
background : var ( --void-color-error-subtle );
color : var ( --void-color-error );
background : var ( --void-color-success-subtle );
color : var ( --void-color-success );
Override tokens at any scope to customize a subtree:
--void-color-accent : # 3b82f6 ;
--void-color-accent-hover : # 2563eb ;
--void-color-text-on-accent : # ffffff ;
Every Voidable component inside .branded-section will pick up the new accent color automatically.