Set
--bq-brand and the other root semantics here, in the theme. To style UI with the brand color, use the mode role --bq-ui--brand instead, as described in Color architecture.Namespace your theme using the
bq-theme attribute (e.g., bq-theme="my-custom-theme") or a matching CSS class (e.g., .my-custom-theme).Step-by-step guide
1
Define root semantics
Create a CSS file for your custom theme (e.g.,
custom-theme.css) and set the root tokens. Give each intent you change all five steps — see Intent scale for what each step is used for:2
Adjust mode roles (optional)
Override mode roles only where the defaults don’t fit your palette. The most common cases are the on-color of a solid fill, the focus color, and neutral surfaces:The full list of mode roles and their defaults is in Colors → Mode roles. Hover and active colors aren’t roles you set per component: BEEQ mixes them from the rest color with
--bq-hover and --bq-active, so they follow your overrides.3
Apply your custom theme
Include your custom theme CSS file in your project and set the Pick the setup that matches your project:The Set the theme and mode on the root element from your app entry so the attributes are present before any component renders:To switch to dark mode, change the You can also use CSS classes instead of HTML attributes:
bq-theme and bq-mode attributes on the <html> element.bq-mode is optional for light mode: without it, the root element uses BEEQ’s light mode roles plus the :not([bq-mode]) overrides from the previous step. Set bq-mode="dark" (or the .dark class) to switch to dark mode.Always load
beeq.css before your custom theme CSS so that your variables correctly override the defaults.@beeq/tailwindcss preset maps BEEQ tokens to Tailwind utility classes but does not define your custom theme. Keep the custom theme CSS as a separate file that overrides --bq-* variables, and load it after beeq.css.With Tailwind v4,
@beeq/tailwindcss 1.16.2 and earlier fail with @plugin (b is not a function). On those versions, use @config "@beeq/tailwindcss"; instead.bq-mode attribute:Full example: Nebula theme
Nebula pairs a fuchsia brand with a cyan accent on violet-tinted neutrals, and adds rounder corners and Space Grotesk type. It changes every component in three short layers:- Root semantics. Brand, accent and the neutral scale, plus the font and radius tokens. BEEQ’s mode roles read from these, so light and dark mode follow on their own.
- Mode roles. Four dark-mode overrides: solid brand and accent fills switch to their bright steps, with dark text on top.
- Component variables. Two component-level choices: cards sit on the raised surface with a hairline border, and the progress bar uses the accent instead of the brand, on a cyan-tinted track in dark mode.
Every Nebula value passes the contrast checklist in light and dark mode. If you change a color, check the pairs it affects again.
How overrides work
BEEQ wraps every theme and mode selector in:where(), for example :where([bq-mode="dark"]). :where() has zero specificity, so any selector you write — :root, .promo, [bq-theme="my-custom-theme"], or a component tag — wins over BEEQ’s defaults, whichever stylesheet loads first. You don’t need !important or extra selector weight.
Mode roles reference root semantics (e.g.,
--bq-ui--brand: var(--bq-brand)), and CSS resolves var() on the element that declares the role. Roles are declared on the theme/mode element, usually <html>, so overriding a root semantic deeper in the tree doesn’t re-derive the roles below it. Override the role itself in that case.Override levels
Pick the narrowest level that covers your change:- Global
- Per mode
- Subtree
- Component
Change root semantics on A mode role set on
:root (or your theme selector). Every mode role that points to them updates in both modes::root (e.g., --bq-text--on-brand) applies in both modes. Use the per-mode level if light and dark need different values.