Skip to content

Frontend Theming

The frontend supports both light and dark themes through CSS variables in frontend/src/index.css.

Theme architecture

Theme state is stored in the app store and applied as the dark class on the document root. Light theme values live in :root; dark theme overrides live in .dark.

Components should use semantic tokens, not hardcoded dark colors.

Core tokens

Backgrounds:

  • --base: page background
  • --surface: cards, panels, menus
  • --surface-2: nested panels and subdued blocks
  • --surface-3: hover states and controls

Text:

  • --text-1: primary text
  • --text-2: secondary text
  • --text-3: muted text and placeholders

Borders:

  • --border: normal borders
  • --border-2: stronger borders and controls

Status:

  • --success
  • --warning
  • --danger
  • --info

Special surfaces:

  • --overlay and --overlay-text for modals/previews
  • --chart-bg and --chart-border for chart tooltips
  • --graph-* tokens for the asset graph canvas

Utility classes

Prefer existing semantic classes:

  • card
  • input
  • btn-primary, btn-secondary, btn-ghost, btn-danger
  • table-row
  • text-primary, text-secondary, text-muted
  • bg-base, bg-surface, bg-surface-2, bg-surface-3
  • border-theme
  • severity/status badge classes

For hover variants, use Tailwind arbitrary values because custom class variants are not generated automatically:

className="hover:bg-[var(--surface-3)] hover:text-[var(--text-1)]"

Component guidance

Do not use dark-only classes such as text-white, bg-gray-900, bg-black, or border-gray-800 for normal UI surfaces. Use semantic tokens instead.

Colored status elements may use fixed hue families, but text must remain readable in both themes. Prefer the badge/status classes or text-success, text-warning, text-danger, and text-info.

Charts and canvas code should read CSS variables with getComputedStyle(document.documentElement) rather than embedding dark colors.

Checklist for new UI

  • Text is readable in light and dark themes.
  • Cards and nested panels use surface tokens.
  • Tables use table-row, border-theme, and semantic text colors.
  • Inputs use input.
  • Empty/loading/error states use semantic text and status tokens.
  • Modals use --overlay and readable overlay/header text.