Themes
Backroad's UI is built on shadcn/ui primitives over Tailwind. Theming has two independent axes:
- Palette (
theme) — a named colour scheme. Built in:default,claude,twitter,supabase, andamethyst-haze. - Mode (
mode) —light,dark, orsystem(follow the OS preference).
End users can change both from the settings menu in the navbar (top-right).
Recommending defaults
As the app maker you can recommend a starting palette and mode via
appearance in the run config:
import { run } from '@backroad/backroad';
run(
(br) => {
// your app
},
{
appearance: {
theme: 'claude', // palette
mode: 'light', // 'light' | 'dark' | 'system'
},
}
);
Both fields are optional — omit either to fall back to the built-in default
(default palette, system mode).
Recommendations vs. the user's choice
This is a recommendation, not a lock. The moment a user picks a palette or mode
themselves, their choice is persisted in the browser (localStorage) and
wins over the app's recommendation on every future visit. Until they pick,
your recommended default applies — so you can keep refining the default for
first-time visitors without overriding anyone who has already chosen.
This is intentionally different from regular Backroad values, which are scoped to a session: theme and mode are durable client-side preferences, not session state.
Reacting to the theme in your script
The palette/mode are purely client-side — your server script doesn't observe
them. If you need theme-aware output (e.g. chart colours), drive it off an
explicit control like br.toggle({ label: 'Dark mode' }) in your script and let
the user pick.
Customizing palettes
Each palette is a set of CSS variables (shadcn tokens such as --primary,
--secondary, --muted, --card) defined in the frontend's styles.css:
:root holds the default palette and each named palette lives in a
[data-theme="…"] block (with a .dark variant). To add a palette, add a
matching CSS block and register it in the theme list — there's no run-time
palette override beyond the appearance recommendation above.