Brand Themes

Ship multiple brand identities from a single codebase.

Overview

Brand themes let teams re-skin Byteion UI for different products, clients, SaaS dashboards, admin panels, ecommerce back offices, ERP and POS tools, templates, starter kits, and white-label applications — without rewriting component markup.

Themes work by overriding CSS variables. Components continue using semantic token classes like bg-card, text-foreground, border-border, bg-primary, text-primary-foreground, and shadow-card. Changing the theme changes the visual output while preserving the component API, props, and class structure.

Live preview

This card uses semantic tokens. Switch the theme picker in the navbar to re-skin it instantly.

50
100
200
300
400
500
600
700
800
900
950

Status colors — --success, --warning, --danger, --info — stay constant across themes. Users should not have to relearn system feedback when the brand changes. Danger, warning, success, and info should remain visually predictable and should also be supported by labels, icons, or copy where needed.

Shipped themes

Byteion ships with three brand themes out of the box. Each is a single CSS file that overrides a handful of semantic and primitive variables.

Default

Blue brand. Supports light and dark mode. A solid default for SaaS dashboards, admin panels, and internal tools.

Acme

Orange brand. Supports light and dark mode. A warmer option for client portals, white-label deployments, and multi-tenant apps.

Midnight

Violet brand. Always dark by default. Designed for analytics dashboards, operations centers, and dark-first applications.

Midnight does not require the .dark class — its variables are already tuned for dark surfaces. If you adopt Midnight, test charts, logos, illustrations, and embedded content against dark backgrounds to ensure they remain legible.

How theme selection works

Themes are activated through HTML attributes on the <html> element. The selector structure is:

No attribute
Default theme, light mode. The :root variables from variables.css apply.
<html lang="en">
class="dark"
Default theme, dark mode. The .dark overrides in variables.css apply.
<html lang="en" class="dark">
data-theme="acme"
Acme theme, light mode. Variables from [data-theme="acme"] override the defaults.
<html lang="en" data-theme="acme">
data-theme="acme" class="dark"
Acme theme, dark mode. Variables from [data-theme="acme"].dark apply.
<html lang="en" data-theme="acme" class="dark">
data-theme="midnight"
Midnight theme. Always dark — the variables themselves are tuned for dark surfaces, so no .dark class is needed.
<html lang="en" data-theme="midnight">

Anatomy of a brand theme

A brand theme is a CSS file that overrides semantic color variables under a [data-theme="..."] selector. An optional .dark variant handles the dark palette. Theme files live in packages/core/theme/themes/.

[data-theme="acme"] {
  /* Semantic surfaces — warmer whites */
  --background: 30 50% 99%;
  --foreground: 30 20% 8%;
  --card: 0 0% 100%;
  --popover: 0 0% 100%;
  --muted: 30 30% 96%;
  --muted-foreground: 30 15% 38%;
  --border: 30 20% 88%;
  --input: 30 20% 88%;

  /* Brand */
  --primary: 24 95% 47%;
  --primary-foreground: 0 0% 100%;
  --ring: 24 95% 53%;

  /* Optional primitive primary scale — controls bg-primary-50 through bg-primary-950 */
  --palette-primary-50:  33 100% 96%;
  --palette-primary-500: 25 95%  53%;
  --palette-primary-600: 21 90%  48%;
  --palette-primary-700: 17 88%  40%;
  /* Full 11-step ramp in the actual file */
}

[data-theme="acme"].dark {
  --background: 24 15% 6%;
  --foreground: 30 30% 96%;
  --card: 24 15% 9%;
  --popover: 24 15% 9%;
  --muted: 24 8% 14%;
  --muted-foreground: 30 10% 65%;
  --border: 24 8% 18%;
  --input: 24 8% 18%;
  --primary: 24 95% 60%;
  --primary-foreground: 30 10% 5%;
}

Only override the variables you need to change. Unspecified variables fall through to the default theme. Status colors (--success, --warning, --danger, --info) are intentionally not overridden so they remain recognisable across brands.

Applying a theme

Set a single attribute on <html>. No JavaScript framework required:

Default
<html lang="en">
Default + dark
<html lang="en" class="dark">
Brand "acme"
<html lang="en" data-theme="acme">
"midnight" (always dark)
<html lang="en" data-theme="midnight">

Author your own brand

Creating a custom brand theme for your product, client, or white-label deployment takes five steps:

  1. Create the file. Add packages/core/theme/themes/<your-brand>.css.
  2. Override semantic variables. Define [data-theme="<your-brand>"] and [data-theme="<your-brand>"].dark with the surface, foreground, border, brand, and focus-ring values you need. You do not have to redefine everything — unspecified variables fall through to the default theme.
  3. Optionally override the primary palette. Set --palette-primary-50 through --palette-primary-950 so primitive utilities like bg-primary-600 re-skin too.
  4. Register the theme. Import the custom theme file after @byteion/core so your overrides take precedence:
    @import "@byteion/core";
    @import "./themes/<your-brand>.css";
    If you are working inside the Byteion monorepo, add the file to byteion-theme.css alongside the shipped themes.
  5. Check contrast. Run npm run check:contrast in @byteion/core to verify that your theme passes WCAG AA for text, surfaces, and interactive states.

Production checklist

Before shipping a custom brand theme or switching themes at runtime, verify these areas:

  • Primary button contrast. Check bg-primary against text-primary-foreground in both light and dark variants of every theme.
  • Muted text readability. text-muted-foreground must remain legible on bg-background, bg-card, and bg-popover surfaces.
  • Focus ring visibility. Tab through inputs, buttons, links, and menus. ring-primary must be visible against all surface backgrounds.
  • Status color recognisability. Ensure --success, --warning, --danger, and --info remain distinct from brand colors and from each other.
  • Charts, logos, and avatars. Verify that third-party content, embedded charts, logos, avatars, and empty states are legible on the new surface colors.
  • Cross-framework consistency. Check that HTML, React, and Vue examples render with the same visual output under each theme.
  • Persistence. If users can switch themes, persist the selected theme in localStorage so it survives page reloads and navigation.
  • Theming Guide — Override variables, customize the primary color, and use the three token layers
  • Dark Mode — Toggle scripts, persistence, and dark-aware semantic tokens
  • Design Tokens — The full token architecture

Unlock Premium Patterns

Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.

Explore Pro Components