BridgeHandbookDraft
For agents
Menu
Draft

Theming

Light and dark, and how tokens switch between them.

How themes work

A theme is the data-theme attribute on <html>: light or dark. Every token has a value for each, so changing the attribute recolours the whole page. Components don't need any dark-mode code.

Because themes are attributes, any element can set its own: a data-theme="dark" box shows dark inside a light page. The handbook's example previews work this way.

Switching

  • People choose Light or Dark in Settings → Appearance. There's no toggle in the top bar.
  • The choice is saved in the browser and applied before the first paint, so a dark-mode user never sees a white flash.
  • Tailwind's dark: follows the same attribute. But don't use dark: to fix a color; fix the token.
// In the root layout's <head>, before anything paints:
<script dangerouslySetInnerHTML={{ __html:
  `try{if(localStorage.getItem("theme")==="dark")document.documentElement.dataset.theme="dark"}catch(e){}`
}} />

// On <html>: the attribute changes after the server render, so React shouldn't warn.
<html lang="en" suppressHydrationWarning>

Images in dark mode

Logos and graphics with a dark version can't know the theme during the server render. Render a placeholder first, then swap in the right image once the page is running in the browser.

Rules

Colors are tokens

Components use role tokens only: bg-[var(--surface-secondary)], text-[var(--text-muted)]. Never hex, rgb() or Tailwind palette classes such as bg-blue-500, and never a dark: patch to fix a color: if dark mode looks wrong, fix the token.

Not decided yet

Until these are settled, follow Bridge OS as it is today.

  • Following the device setting. Bridge OS offers Light and Dark only (no "System"). Whether other apps should follow the device is undecided.
  • Each app's identity marker (open question #16): whether apps get one small color of their own, and where it may appear.

Sources

  • Bridge OS DESIGN.md → Dark Mode.
  • Package globals.css (light block answers to :root and [data-theme="light"]; dark to [data-theme="dark"]).