# Theme Overrides

Source: https://lumeo.nativ.sh/docs/theme-overrides

# Theme Overrides

Lumeo's theme system is a layered set of CSS custom properties. The library ships seven built-in themes (Zinc, Blue, Green, Rose, Violet, Amber, Teal) in both light and dark mode. You override the theme at three levels: globally with CSS variables, per-mode with dark-mode swaps, and per-component with the `Class` parameter. Every Lumeo component reads colors from variables — there are no hard-coded hex values anywhere in the library — so a variable change cascades to every component on the page.

## The variable system

Variables are declared on `:root` for light mode and re-declared on `.dark` for dark mode. They come in foreground / background pairs — every surface variable has a matching `-foreground` for readable text on top.

Variable

Used by

`--color-background` / `--color-foreground`

Page surface and primary text.

`--color-card` / `--color-card-foreground`

Card, Sheet, Popover, Dropdown, Dialog body.

`--color-primary` / `--color-primary-foreground`

Primary button, active links, accent fills.

`--color-secondary` / `--color-secondary-foreground`

Secondary button, subtle chips.

`--color-muted` / `--color-muted-foreground`

Muted surfaces (skeletons, code blocks) and secondary text.

`--color-accent` / `--color-accent-foreground`

Hover backgrounds for menu items, navigation links.

`--color-destructive` / `--color-destructive-foreground`

Destructive buttons, invalid form rings, error alerts.

`--color-border`

Default border for inputs, cards, dividers.

`--color-input`

Form input borders.

`--color-ring`

Focus-visible ring color.

`--radius`

Base border-radius. Components derive `--radius-sm` / `--radius-xl` from it.

## Global override

To re-skin the entire app, override the variables in your own stylesheet loaded _after_ `lumeo.css`. Use OKLCH for colors — the built-in themes do — so contrast stays predictable when you tweak lightness.

/\* my-app.css — loaded after lumeo.css \*/
:root {
    --color-primary: oklch(0.55 0.22 250);
    --color-primary-foreground: oklch(0.98 0 0);
    --color-ring: oklch(0.55 0.22 250);
    --radius: 0.5rem;
}

## Dark mode swaps

Lumeo does not use Tailwind's `dark:` prefix anywhere internally. Dark mode flips the same variables under the `.dark` class on `<html>`. Your overrides must declare both blocks or dark mode will fall back to the library defaults for anything you didn't redeclare.

:root {
    --color-background: oklch(1 0 0);
    --color-foreground: oklch(0.15 0 0);
    --color-primary: oklch(0.55 0.22 250);
    --color-primary-foreground: oklch(0.98 0 0);
}

.dark {
    --color-background: oklch(0.15 0 0);
    --color-foreground: oklch(0.98 0 0);
    --color-primary: oklch(0.65 0.18 250);
    --color-primary-foreground: oklch(0.15 0 0);
}

The `.dark` class is toggled by the [ThemeService](docs/services/theme). Don't toggle it yourself unless you also persist the choice.

## Scoped override

Variables cascade, so you can re-declare them on any ancestor element to re-skin only the subtree below it. Useful for an embedded widget that should look "branded" while sitting inside a neutral app shell.

<div class="embedded-widget" style="--color-primary: oklch(0.6 0.2 30); --color-ring: oklch(0.6 0.2 30);">
    <Card>
        <Stack Gap="3" Class="p-4">
            <Heading Level="3">Promo</Heading>
            <Button>Get started</Button>
        </Stack>
    </Card>
</div>

## Per-component class overrides

Every Lumeo component accepts `Class`, appended to the component's base classes via `$"{BaseClasses} {Class}".Trim()`. Use it to add utilities (margins, hover states, sizing). For colors, prefer pointing at theme variables — `bg-primary`, `text-foreground` — so the override still respects light and dark mode.

<!-- good: theme-aware utilities -->
<Button Class="bg-success text-success-foreground hover:bg-success/90">Mark complete</Button>

<!-- good: spacing / sizing -->
<Card Class="max-w-md mx-auto shadow-xl">...</Card>

<!-- avoid: raw hex breaks in dark mode -->
<Button Class="bg-\[#1e40af\] text-white">Don't do this</Button>

Avoid raw hex / rgb in `Class`. They look right in light mode and break in dark mode because they don't participate in the variable swap.

## Picking the right layer

Goal

Layer

Brand color across the whole app

Global override of `--color-primary` + dark variant.

Different look for an embedded marketing widget

Scoped override on the widget's wrapper.

One specific button needs a custom hue

Per-component `Class` with theme utilities.

Switch users between built-in themes

ThemeService + [ThemeSwitcher](components/theme-switcher).

Round all corners more

Global override of `--radius`.

## Demo: scoped theme

Wrap any subtree in a div that re-declares the variables. The card and button below pick up a violet accent without affecting anything else on this page.

### Scoped accent

This card lives inside an override block.

Primary Outline

## See also

-   [Theme Service](docs/services/theme) — toggling and persisting themes
-   [Theme Switcher](components/theme-switcher) — built-in switcher component
-   [Theme Toggle](components/theme-toggle) — light/dark toggle
-   [Accessibility](docs/accessibility) — contrast guarantees
