@renge-ui/tokens
System
Token API reference, animation system, and composition patterns. The mathematical foundation made programmable.
Token API
@renge-ui/tokens exports two ways to consume tokens: createRengeTheme() for generating CSS, and rengeVars for typed CSS variable references.
createRengeTheme(config?)
Generates a complete token set from mathematical first principles. Returns CSS ready to inject and a JS vars map.
import { createRengeTheme } from "@renge-ui/tokens";
const theme = createRengeTheme({
profile: "ocean", // 'ocean' | 'earth' | 'twilight' | 'fire' | 'void' | 'leaf'
mode: "light", // 'light' | 'dark'
baseUnit: 4, // Spacing multiplier in px — try 6 for denser UIs
typeBase: 16, // Root font size in px
scaleRatio: 1.618, // Typography scale ratio (φ = golden ratio)
variance: 0, // 0–1 tolerance drift (0 = exact math, deterministic)
selector: ":root", // CSS selector to wrap the variables in
});
// theme.css — full :root { --renge-* ... } string, ready to inject
// theme.vars — Record<string, string> of every --renge-* variable
// theme.config — resolved config with all defaults appliedrengeVars
A statically typed object of CSS variable references. No runtime dependency — IDE autocomplete for every token.
import { rengeVars } from "@renge-ui/tokens";
// Color (22 semantic tokens, profile-reactive)
rengeVars.color.bg // "var(--renge-color-bg)"
rengeVars.color.accent // "var(--renge-color-accent)"
rengeVars.color.danger // "var(--renge-color-danger)"
// Spacing (Fibonacci × baseUnit, steps 0–10)
rengeVars.space[3] // "var(--renge-space-3)" → 12px (Fib 3 × 4)
rengeVars.space[5] // "var(--renge-space-5)" → 32px (Fib 8 × 4)
// Typography (PHI scale, 8 steps)
rengeVars.fontSize.base // "var(--renge-font-size-base)"
rengeVars.fontSize.lg // "var(--renge-font-size-lg)"
rengeVars.lineHeight.base // "var(--renge-line-height-base)"
// Motion (Fibonacci × 100ms, steps 0–10)
rengeVars.duration[2] // "var(--renge-duration-2)" → 200ms
rengeVars.duration[5] // "var(--renge-duration-5)" → 800ms
rengeVars.easing.out // "var(--renge-easing-ease-out)"
rengeVars.easing.spring // "var(--renge-easing-spring)"
// Radius (Fibonacci × baseUnit, steps none/1–5/full)
rengeVars.radius[2] // "var(--renge-radius-2)" → 8px
rengeVars.radius.full // "var(--renge-radius-full)" → pill
// Layout (PHI-derived containers, Fibonacci column min-widths, φ aspect ratios)
rengeVars.container.sm // "var(--renge-container-sm)" → 524px (200 × φ²)
rengeVars.container.lg // "var(--renge-container-lg)" → 1371px (200 × φ⁴)
rengeVars.colMin.sm // "var(--renge-col-min-sm)" → 272px (34 × 8px)
rengeVars.aspect.golden // "var(--renge-aspect-golden)" → 1.618034 (φ)
rengeVars.aspect.vertical // "var(--renge-aspect-vertical)" → 0.618034 (1/φ)Bridging to another system
Use rengeVars to map Renge tokens to your own CSS variable names — no string construction.
import { createRengeTheme, rengeVars } from "@renge-ui/tokens";
const theme = createRengeTheme({ profile: "earth", mode: "light" });
const aliases: [string, string][] = [
["--color-bg-primary", rengeVars.color.bg],
["--color-bg-secondary", rengeVars.color.bgSubtle],
["--color-primary", rengeVars.color.accent],
["--color-error", rengeVars.color.danger],
["--space-sm", rengeVars.space[2]],
["--space-md", rengeVars.space[4]],
];
const aliasCSS = `:root {
${aliases.map(([k, v]) => ` ${k}: ${v};`).join("\n")}
}`;
document.head.insertAdjacentHTML("beforeend", `<style>${theme.css}\n${aliasCSS}</style>`);Spacing tokens — --renge-space-{0–10}
Each step is FIBONACCI[n] × baseUnit. Default baseUnit = 4px. Growth is non-linear by design.
| Token | Fibonacci | Default (baseUnit=4) |
|---|---|---|
| --renge-space-0 | 0 | 0px |
| --renge-space-1 | 1 | 4px |
| --renge-space-2 | 2 | 8px |
| --renge-space-3 | 3 | 12px |
| --renge-space-4 | 5 | 20px |
| --renge-space-5 | 8 | 32px |
| --renge-space-6 | 13 | 52px |
| --renge-space-7 | 21 | 84px |
| --renge-space-8 | 34 | 136px |
| --renge-space-9 | 55 | 220px |
| --renge-space-10 | 89 | 356px |
Typography tokens — --renge-font-size-{size}
Formula: typeBase × scaleRatio^n. Default typeBase = 16px, scaleRatio = φ. Steps use fractional exponents for finer gradation at the small end.
| Token | Formula | Default |
|---|---|---|
| --renge-font-size-xs | base × φ^−0.5 | ~12.6px |
| --renge-font-size-sm | base × φ^−0.25 | ~14.2px |
| --renge-font-size-base | base × φ⁰ | 16px |
| --renge-font-size-lg | base × φ¹ | ~25.9px |
| --renge-font-size-xl | base × φ² | ~41.9px |
| --renge-font-size-2xl | base × φ³ | ~67.8px |
| --renge-font-size-3xl | base × φ⁴ | ~109.7px |
| --renge-font-size-4xl | base × φ⁵ | ~177.4px |
Radius tokens — --renge-radius-{step}
Steps 1–5 follow Fibonacci × baseUnit. full = 9999px pill.
| Token | Default |
|---|---|
| --renge-radius-none | 0px |
| --renge-radius-1 | 4px (Fib 1 × 4) |
| --renge-radius-2 | 8px (Fib 2 × 4) |
| --renge-radius-3 | 12px (Fib 3 × 4) |
| --renge-radius-4 | 20px (Fib 5 × 4) |
| --renge-radius-5 | 32px (Fib 8 × 4) |
| --renge-radius-full | 9999px — pill |
Layout tokens
Container widths, responsive column min-widths, and aspect ratios — all derived from φ and Fibonacci.
rengeVars.container.sm // "var(--renge-container-sm)" → 524px (200 × φ²)
rengeVars.container.md // "var(--renge-container-md)" → 847px (200 × φ³)
rengeVars.container.lg // "var(--renge-container-lg)" → 1371px (200 × φ⁴) ← default
rengeVars.container.xl // "var(--renge-container-xl)" → 2218px (200 × φ⁵)
rengeVars.container.full // "var(--renge-container-full)" → 100%
rengeVars.colMin.xs // "var(--renge-col-min-xs)" → 168px (Fib 21 × 8)
rengeVars.colMin.sm // "var(--renge-col-min-sm)" → 272px (Fib 34 × 8)
rengeVars.colMin.md // "var(--renge-col-min-md)" → 440px (Fib 55 × 8)
rengeVars.colMin.lg // "var(--renge-col-min-lg)" → 712px (Fib 89 × 8)
rengeVars.aspect.square // "var(--renge-aspect-square)" → 1
rengeVars.aspect.golden // "var(--renge-aspect-golden)" → 1.618034 (φ)
rengeVars.aspect.vertical // "var(--renge-aspect-vertical)" → 0.618034 (1/φ)
rengeVars.aspect.video // "var(--renge-aspect-video)" → 1.777778 (16/9)
rengeVars.aspect.classic // "var(--renge-aspect-classic)" → 1.333333 (4/3)All 22 semantic color tokens
| rengeVars key | CSS variable | Role |
|---|---|---|
| color.bg | --renge-color-bg | Page background |
| color.bgSubtle | --renge-color-bg-subtle | Slightly elevated surface |
| color.bgMuted | --renge-color-bg-muted | Muted surface |
| color.bgInverse | --renge-color-bg-inverse | Inverted background |
| color.fg | --renge-color-fg | Primary text |
| color.fgSubtle | --renge-color-fg-subtle | Secondary text |
| color.fgMuted | --renge-color-fg-muted | Placeholder / disabled |
| color.fgInverse | --renge-color-fg-inverse | Text on inverse bg |
| color.border | --renge-color-border | Default divider |
| color.borderSubtle | --renge-color-border-subtle | Hairline divider |
| color.borderFocus | --renge-color-border-focus | Keyboard focus ring |
| color.accent | --renge-color-accent | Primary interactive |
| color.accentHover | --renge-color-accent-hover | Hover state |
| color.accentSubtle | --renge-color-accent-subtle | Tinted background |
| color.success | --renge-color-success | Positive outcome |
| color.successSubtle | --renge-color-success-subtle | Success tint bg |
| color.warning | --renge-color-warning | Caution |
| color.warningSubtle | --renge-color-warning-subtle | Warning tint bg |
| color.danger | --renge-color-danger | Error / destructive |
| color.dangerSubtle | --renge-color-danger-subtle | Danger tint bg |
| color.info | --renge-color-info | Informational |
| color.infoSubtle | --renge-color-info-subtle | Info tint bg |
Animations
15 named animations derived from the token system. Apply via the animation prop on any component, or directly via the CSS variable.
All 15 tokens — live
Live examples
breathe
floatpulsewave
swelling{/* animation prop — available on Heading, Text, Card, Section, Badge, and more */}
<Heading level={2} animation="breathe">Living proportion.</Heading>
<Badge variant="accent" animation="pulse">New</Badge>
<Card animation="bloom"><Text>Enters with bloom.</Text></Card>
{/* Via CSS variable — works on any element */}
<div style={{ animation: "var(--renge-animation-float)" }}>
Floats gently.
</div>
{/* Duration tokens govern speed — Fibonacci × 100ms */}
/* breathe → var(--renge-duration-10) = 8900ms (slow, organic) */
/* vibrate → var(--renge-duration-6) = 1300ms (quick, alert) */@keyframes blocks and their --renge-animation-* CSS variables are generated by createRengeTheme() — no separate import needed. Durations reference --renge-duration-* tokens derived from Fibonacci × 100ms.Components with animation prop
The animation prop is available on: Heading, Text, Card, Section, Button, IconButton. All other elements can use the CSS variable directly via the style prop.
{/* animation prop — typed to AnimationName */}
<Heading level={2} animation="breathe">Living proportion.</Heading>
<Text size="lg" animation="float">Natural mathematics.</Text>
<Card animation="bloom"><Text>Enters with bloom.</Text></Card>
<Button animation="pulse">Subscribe</Button>
{/* Any element — via CSS variable */}
<div style={{ animation: "var(--renge-animation-spiral-in)" }}>
Custom element.
</div>
{/* Combine with duration tokens for speed control */}
<div style={{
animation: "var(--renge-animation-float)",
animationDuration: "var(--renge-duration-7)", // 2100ms — faster than default
}}>
Faster float.
</div>Easing tokens — --renge-easing-{curve}
All control points derived from φ: A = 1/φ² ≈ 0.382, B = 1/φ ≈ 0.618. Use these on any CSS transition or animation.
| Token | Curve | Use |
|---|---|---|
| --renge-easing-linear | linear | Progress bars, scrubbing |
| --renge-easing-ease-out | cubic-bezier(0.382, 1, 0.618, 1) | Entrances — fast start, slow settle |
| --renge-easing-ease-in | cubic-bezier(0.382, 0, 1, 0.618) | Exits — slow start, fast end |
| --renge-easing-ease-in-out | cubic-bezier(0.382, 0, 0.618, 1) | Balanced state transitions |
| --renge-easing-spring | cubic-bezier(0.382, 0.618, 0.618, 1.382) | Playful overshoot |
{/* Tailwind utility classes */}
<div class="ease-renge-ease-out duration-renge-3 transition-all">
Entrances.
</div>
{/* CSS directly */}
.my-element {
transition: transform var(--renge-duration-3) var(--renge-easing-ease-out);
}
{/* rengeVars — no string construction */}
import { rengeVars } from "@renge-ui/tokens";
style={{ transition: `opacity ${rengeVars.duration[3]} ${rengeVars.easing.out}` }}Duration reference
| Token | Value | Fibonacci derivation |
|---|---|---|
| --renge-duration-1 | 100ms | Fib 1 × 100ms |
| --renge-duration-2 | 200ms | Fib 2 × 100ms |
| --renge-duration-3 | 300ms | Fib 3 × 100ms |
| --renge-duration-4 | 500ms | Fib 5 × 100ms |
| --renge-duration-5 | 800ms | Fib 8 × 100ms — motion default |
| --renge-duration-6 | 1300ms | Fib 13 × 100ms |
| --renge-duration-7 | 2100ms | Fib 21 × 100ms — toast timeout |
| --renge-duration-8 | 3400ms | Fib 34 × 100ms |
| --renge-duration-9 | 5500ms | Fib 55 × 100ms — most animations |
| --renge-duration-10 | 8900ms | Fib 89 × 100ms — breathe, bloom |
Accessibility
Renge components and tokens are built to WCAG 2.1 Level AA accessibility standards. Every interactive component meets or exceeds the Web Content Accessibility Guidelines, ensuring interfaces built with Renge are usable by everyone.Color Contrast — All 6 Profiles
Ensuring sufficient contrast between foreground and background hues is vital for users with low vision or color deficiencies. All 6 profiles meet WCAG AA (4.5:1 minimum for text, 3:1 for large text and UI elements) in both light and dark modes. Use a tool like WebAIM's Contrast Checker to validate specific color combinations in your application.WCAG 2.1 Compliance Checklist
Component-Level Features
Touch Targets
Full-size buttons, links, and inputs enforce a 44×44px minimum touch target. Compact variants are sized for context (WCAG 2.2 minimum is 24×24px).Color Contrast
All text across light and dark modes meets WCAG AA (4.5:1) across all 6 color profiles. Validate your specific combinations using WebAIM's Contrast Checker.Keyboard Navigation
Every interactive component implements ARIA keyboard patterns. Overlays (Modal, Drawer) trap focus. Menus support arrow-key navigation. All triggers return focus on close.Screen Reader Support
Proper ARIA labels, roles, and live regions throughout. aria-expanded, aria-haspopup, aria-selected, aria-current, aria-modal, and aria-live used correctly.Motion Preferences
All animations and transitions respect prefers-reduced-motion. Users who prefer reduced motion experience instant, flicker-free interactions.Semantic HTML
Components use correct semantic elements. Interactive controls are buttons or links. Form fields are associated with labels. Page landmarks are properly structured.Keyboard Patterns
| Component | Keys | Behavior |
|---|---|---|
| Button / IconButton | Enter, Space | Activate |
| Tabs | ← → Arrow, Home, End | Navigate between tabs (roving tabindex) |
| RadioGroup | ↑ ↓ ← → Arrow | Select next/previous radio (roving tabindex) |
| Rating | ← → Arrow, Home, End | Decrease/increase value; Home = 0, End = max |
| Accordion | Enter, Space | Toggle panel open/closed |
| Modal | Esc, Tab, Shift+Tab | Close on Esc; Tab cycles through focusable elements; focus returns to trigger on close |
| Drawer | Esc, Tab, Shift+Tab | Close on Esc; focus trap within panel; focus returns to trigger on close |
| DropdownMenu | Enter/Space to open, ↑ ↓ Arrow, Home, End, Esc | Open/close; arrow keys navigate items; Esc closes and returns focus to trigger |
| Popover | Enter/Space to toggle, Esc | Toggle open/close; Esc closes and returns focus to trigger |
| Combobox | ↑ ↓ Arrow, Enter, Esc, Home, End | Arrow keys navigate filtered list; Enter selects highlighted; Esc closes; focus stays on input |
| MultiSelect | Enter/Space to open, ↑ ↓ Arrow, Enter on option, Esc | Open/close; arrow keys navigate options; Enter/Space toggles selection; Esc closes |
| ContextMenu | Esc, ↑ ↓ Arrow | Esc closes; arrow keys navigate menu items when open |
| Checkbox / Switch | Space | Toggle checked state |
| Select | ↑ ↓ Arrow, Enter, Esc | Native browser behavior (delegated to <select>) |
| Slider | ← → Arrow, Home, End | Decrease/increase value (native <input type=range>) |
| NumberInput | ↑ ↓ Arrow (on input) | Increment/decrement value via native number input |
| Stepper | Enter, Space | Navigate to step when onStepChange is provided |
| Pagination | Tab, Enter, Space | Tab between page buttons; Enter/Space activates |
| TagInput | Enter or , to add, Backspace to remove last | Add tag on Enter or comma; remove last tag on Backspace when input is empty |
| Tooltip | Focus / Blur | Show on focus; hide on blur |
WCAG 2.1 Level AA
Renge components meet WCAG 2.1 Level AA. All 6 color profiles (Ocean, Earth, Leaf, Twilight, Fire, Void) pass 4.5:1 contrast in both light and dark modes. All interactive components implement proper ARIA patterns and keyboard navigation. Interfaces built with Renge are accessible to users with disabilities by default.Patterns
Common composition patterns using @renge-ui/react components. Every value resolves to a CSS custom property — switch profiles and all colors update instantly.
Status card
Build status
PassingLast run 2 minutes ago
Form with validation
Metric grid
{/* Every component uses only CSS custom properties */}
{/* Switch profiles and all colors update instantly — no re-render */}
import { createRengeTheme } from "@renge-ui/tokens";
const theme = createRengeTheme({ profile: "twilight" });
// Inject theme.css — all @renge-ui/react components adapt automatically.var(--renge-*) CSS custom properties. Switch color profiles by swapping the injected theme block — no component state changes required.