Skip to Content
Livery is in early development. Star us on GitHub!
@livery/coreCSS Utilities

CSS Utilities

Generate CSS custom properties from theme values for easy styling.

Why CSS Variables?

Problem: Your theme data is a JavaScript object, but your styles need values. How do you connect them?

Solution: Convert theme data to CSS custom properties (variables). Then use those variables in Tailwind, CSS, or any styling approach.

Theme Object → CSS Variables → Styles { colors: { primary: '#14B8A6' } } → --colors-primary: #14B8A6 → bg-primary

Which Function Should I Use?

FunctionUse when…
toCssVariables()You need variables as a JavaScript object (inline styles, custom injection)
toCssString()You need a CSS string for a single theme
toCssStringAll()You need CSS for multiple static themes (light/dark mode)
cssVar()You need a single var(--path) reference
createCssVarHelper()You want a typed helper for var() references in components

When to Use CSS Utilities Directly

ScenarioRecommendation
Using DynamicThemeProviderDon’t — the provider handles CSS injection automatically
Server-side CSS injectionUse toCssString() — generate CSS in your layout
Building a style objectUse toCssVariables() — get key-value pairs
Referencing vars in CSS-in-JSUse createCssVarHelper() — type-safe var() references
Custom rendering (canvas, SVG)Use hooks instead — useThemeValue() gives actual values

Tip: Most users don’t need these directly. DynamicThemeProvider and getLiveryData() handle CSS generation for you.

Generating CSS Variables

toCssVariables

Convert a theme to a CSS variables object:

import { createSchema, t, toCssVariables, type InferTheme } from '@livery/core'; const schema = createSchema({ definition: { colors: { primary: t.color(), background: t.color(), }, spacing: { md: t.dimension(), }, }, }); type Theme = InferTheme<typeof schema.definition>; const theme: Theme = { colors: { primary: '#14B8A6', background: '#FFFFFF', }, spacing: { md: '16px', }, }; const cssVars = toCssVariables({ schema, theme }); // { // '--colors-primary': '#14B8A6', // '--colors-background': '#FFFFFF', // '--spacing-md': '16px', // }

With Prefix

Add a prefix to all variable names:

const cssVars = toCssVariables({ schema, theme, options: { prefix: 'livery' }, }); // { // '--livery-colors-primary': '#14B8A6', // '--livery-colors-background': '#FFFFFF', // '--livery-spacing-md': '16px', // }

Custom Separator

Change the separator between path segments:

const cssVars = toCssVariables({ schema, theme, options: { separator: '_' }, }); // { // '--colors_primary': '#14B8A6', // ... // }

Generating CSS String

toCssString

Generate a CSS string for injection:

import { toCssString } from '@livery/core'; const css = toCssString({ schema, theme }); // :root { // --colors-primary: #14B8A6; // --colors-background: #FFFFFF; // --spacing-md: 16px; // }

Custom Selector

const css = toCssString({ schema, theme, selector: '[data-theme="light"]', }); // [data-theme="light"] { // --colors-primary: #14B8A6; // ... // }

Generating CSS for Multiple Themes

toCssStringAll

Generate CSS for multiple static themes at once. This is ideal for light/dark mode or any predefined theme variants — no runtime CSS regeneration needed.

import { createSchema, t, toCssStringAll, type InferTheme } from '@livery/core'; const schema = createSchema({ definition: { colors: { primary: t.color(), background: t.color(), foreground: t.color(), }, }, }); type Theme = InferTheme<typeof schema.definition>; const light: Theme = { colors: { primary: '#14B8A6', background: '#FFFFFF', foreground: '#0F172A', }, }; const dark: Theme = { colors: { primary: '#2DD4BF', background: '#0F172A', foreground: '#F8FAFC', }, }; const css = toCssStringAll({ schema, themes: { light, dark }, defaultTheme: 'light', }); // :root, [data-theme="light"] { // --colors-primary: #14B8A6; // --colors-background: #FFFFFF; // --colors-foreground: #0F172A; // } // // [data-theme="dark"] { // --colors-primary: #2DD4BF; // --colors-background: #0F172A; // --colors-foreground: #F8FAFC; // }

Why Use toCssStringAll?

With toCssString(), you generate CSS for one theme at a time. To switch themes, you’d need to regenerate and re-inject CSS. With toCssStringAll(), all themes are in the CSS upfront — switching is just changing a data attribute:

// Toggle is trivial — no CSS regeneration document.documentElement.dataset.theme = 'dark';

Custom Attribute

By default, themes are selected via data-theme. You can customize this:

const css = toCssStringAll({ schema, themes: { light, dark }, defaultTheme: 'light', attribute: 'data-color-scheme', // Custom attribute }); // :root, [data-color-scheme="light"] { ... } // [data-color-scheme="dark"] { ... }

See Static Themes in Next.js for complete implementation examples.

CSS Variable Helper

cssVar

Create CSS variable references:

import { cssVar } from '@livery/core'; const color = cssVar({ path: 'colors.primary' }); // 'var(--colors-primary)' const spacing = cssVar({ path: 'spacing.md', options: { prefix: 'theme' } }); // 'var(--theme-spacing-md)'

createCssVarHelper

Create a reusable helper with preset options:

import { createCssVarHelper } from '@livery/core'; const $ = createCssVarHelper({ schema, options: { prefix: 'livery' }, }); const styles = { color: $('colors.primary'), // 'var(--livery-colors-primary)' padding: $('spacing.md'), // 'var(--livery-spacing-md)' fontFamily: $('typography.sans'), // 'var(--livery-typography-sans)' };

Using in React

import { createCssVarHelper } from '@livery/core'; import { schema } from '@/lib/schema'; const $ = createCssVarHelper({ schema }); function Button({ children }) { return ( <button style={{ backgroundColor: $('colors.primary'), padding: $('spacing.md'), fontFamily: $('typography.fontFamily'), border: 'none', borderRadius: $('borderRadius.md'), }} > {children} </button> ); } // $('colors.primary') returns 'var(--colors-primary)'

Using in CSS

After injecting CSS variables, use them directly:

.button { background-color: var(--colors-primary); color: var(--colors-foreground); padding: var(--spacing-md); font-family: var(--typography-fontFamily); border-radius: var(--borderRadius-md); } .card { background: var(--colors-surface); border: 1px solid var(--colors-border); box-shadow: var(--shadows-md); }

Using with Tailwind

For Tailwind v4, use the @theme directive to map CSS variables:

app/globals.css
@import 'tailwindcss'; @theme { --color-primary: var(--colors-primary); --color-background: var(--colors-background); --color-foreground: var(--colors-foreground); }

Then use semantic Tailwind classes:

<div class="bg-background text-foreground"> <button class="bg-primary text-white"> Click me </button> </div>

For Tailwind v3, extend the theme in your config:

tailwind.config.js
module.exports = { theme: { extend: { colors: { primary: 'var(--colors-primary)', background: 'var(--colors-background)', foreground: 'var(--colors-foreground)', }, }, }, };

API Reference

toCssVariables(options)

function toCssVariables<T extends SchemaDefinition>( options: ToCssVariablesOptions<T> ): Record<string, string> interface ToCssVariablesOptions<T> { schema: Schema<T>; theme: InferTheme<T>; options?: CssVariableOptions; } interface CssVariableOptions { prefix?: string; separator?: string; transformName?: (path: string) => string; }

toCssString(options)

function toCssString<T extends SchemaDefinition>( options: ToCssStringOptions<T> ): string interface ToCssStringOptions<T> { schema: Schema<T>; theme: InferTheme<T>; options?: CssVariableOptions; selector?: string; // Default: ':root' }

toCssStringAll(options)

function toCssStringAll<T extends SchemaDefinition, K extends string>( options: ToCssStringAllOptions<T, K> ): string interface ToCssStringAllOptions<T, K extends string> { schema: Schema<T>; themes: Record<K, InferTheme<T>>; defaultTheme?: K; options?: CssVariableOptions; attribute?: string; // Default: 'data-theme' }

cssVar(options)

function cssVar(options: CssVarOptions): string interface CssVarOptions { path: string; options?: CssVariableOptions; }

createCssVarHelper(options)

function createCssVarHelper<T extends SchemaDefinition>( options: CreateCssVarHelperOptions<T> ): (path: string) => string interface CreateCssVarHelperOptions<T> { schema: Schema<T>; options?: CssVariableOptions; }
Last updated on