Documentation

Foundations

Theming

Re-skin Onda with your own brand — palette and fonts via the CSS-variable contract, with motion staying Onda. Your colors, your type.

Onda's palette and fonts are the default look, not an enforced one. Every component reads its colors and fonts from CSS variables, so you can re-skin the whole catalog with your own brand — your palette, your type, with Onda's motion as a tasteful default you can tune.

Try it live on the Brand playground.

How it works

Each component defaults its color / font props to a var() token with the Onda value as the fallback — for example the accent default is 'var(--onda-accent, #D96B82)'. So:

  • Do nothing → components render in the Onda palette (the fallbacks).
  • Set the --onda-* variables on any ancestor → everything beneath re-skins.

Because the variable is read at render time, there's no per-component wiring: set the variable once at a root and every Onda component inside follows.

What you can override

Surface — color and type — re-skins at runtime. Every component reads its colors and fonts from the --onda-* CSS variables, so setting them on any ancestor (or via the brand prop) re-skins the whole catalog with zero per-component work. The full slot list is below.

Motion is a default, not a lock. Onda's motion grammar — springs, easing, timing, stagger — ships as a tasteful, opinionated default, so the silent case is "quality by construction." But it isn't enforced on you: components are copied into your project as source (ondajs add), so you own the motion and can tune it — a punchier spring, a faster stagger for a hype reel, or edit the house constants in lib/motion.ts to shift the whole catalog at once. Unlike surface slots, motion isn't wired to brand CSS variables today, so there's no runtime brand-level switch for it yet (a motion-override seam is its own techspec); you change it by editing the source you own.

VariableTokenDefault
--onda-bgbackground#08080A
--onda-surfaceraised surface#0E0E12
--onda-surface-2secondary surface#121217
--onda-borderborder#1C1C22
--onda-border-lithover / focus border#26262E
--onda-textprimary text#F2F2F4
--onda-dimsecondary text#8E8E98
--onda-faintlabels / captions#56565F
--onda-accentthe earned accent#D96B82
--onda-accent-softlighter accent step#E89AAB
--onda-font-displaydisplay / headings"Clash Display", sans-serif
--onda-font-bodybody / UI"Space Grotesk", sans-serif

Applying a brand

Plain CSS (no imports)

Components added via ondajs add are copied as source that already reads the variables, so the simplest path is to set them in your own CSS — including pointing the font variables at any font you've loaded in your project (Google Fonts, @fontsource, next/font, a local @font-face, anything):

TSX
:root {
  --onda-accent: #6366f1;
  --onda-text: #f4f4f8;
  --onda-bg: #0b0b12;
  --onda-font-display: "Inter", sans-serif;
  --onda-font-body: "Inter", sans-serif;
}

Scope it to a wrapper instead of :root to theme just one region.

Typed helpers (from the lib)

Prefer a typed object? Onda's lib ships a Brand schema and the brandToCssVars() / <ThemeProvider> helpers (the same ones the renderer uses) — import them from the Onda lib in your project. The CSS approach above needs no imports at all.

TSX
import { brandToCssVars, ThemeProvider } from '@/lib/theme'; // the Onda lib in your project

const brand = {
  accent: '#6366F1',
  text: '#F4F4F8',
  bg: '#0B0B12',
  fontDisplay: '"Inter", sans-serif',
  fontBody: '"Inter", sans-serif',
};

// Spread the CSS variables onto any element…
<div style={brandToCssVars(brand)}>{/* Onda components re-skin here */}</div>;

// …or use the provider wrapper:
<ThemeProvider brand={brand}>{/* … */}</ThemeProvider>;

In a composition

CompositionRenderer takes a brand prop that applies the variables at the composition root, so renders (preview and export) pick up the brand:

TSX
<CompositionRenderer composition={payload} registry={registry} brand={brand} />

Fonts

You are responsible for loading whatever font you reference — Onda only sets the font-family. Load it however your project already does (Google Fonts link, @fontsource, next/font, local @font-face), then point --onda-font-display / --onda-font-body at it. Unset, they fall back to Onda's Clash Display / Space Grotesk.

Authoring components

When you build a component, default every color / font prop to a THEME.* token from lib/tokens.ts — never a raw hex or font string — so it responds to brand overrides out of the box:

TSX
import { THEME } from '@onda/lib/tokens'; // or the copied lib path in a consumer project

accent: z.string().default(THEME.accent),          // 'var(--onda-accent, #D96B82)'
fontFamily: z.string().default(THEME.fontDisplay),  // 'var(--onda-font-display, "Clash Display", …)'