Documentation menu · Guides
Core Concepts

Dark Mode

Build dark-first Liquid Glass interfaces with AuraGlass tokens, readable contrast, restrained glow, and predictable system-theme behavior.

#Start With the App Shell

Dark mode should be decided at the application shell before complex glass surfaces render. Put the theme attribute or class on the document element or on the highest product wrapper, then let AuraGlass components inherit the token values. This keeps overlays, portals, command palettes, drawers, and popovers visually aligned with the rest of the app.

A dark-first AuraGlass page is not simply a black background with bright blur. The material needs enough tint to separate layers, enough border contrast to define edges, and enough text contrast to survive changing imagery behind the glass. Use dark tokens for the backdrop, then use accent color sparingly for active states, charts, badges, and focus rings.

tsx
<html data-theme="dark">
  <body>
    <App />
  </body>
</html>

#Token Strategy

Set global dark tokens for background, surface fill, text, borders, shadows, and accent colors. Keep the system balanced: if blur is high, background opacity usually needs to rise; if the page has bright media, borders and scrims need to become more assertive. The goal is readable premium UI, not maximum transparency.

Use local wrappers when a specific product area needs a different mood. A media player can run darker and more cinematic than a billing page. A monitoring dashboard can use stronger cyan and green accents than a settings view. The shared component API remains the same while the wrapper supplies the local token values.

css
[data-theme='dark'] {
  --glass-bg-default: rgba(6, 9, 15, 0.76);
  --glass-bg-strong: rgba(10, 15, 26, 0.9);
  --glass-text-primary: rgba(255, 255, 255, 0.94);
  --glass-text-secondary: rgba(226, 232, 240, 0.72);
  --glass-border-default: rgba(148, 163, 184, 0.22);
}

#Contrast and Backdrops

Dynamic backdrops are the main dark-mode risk. A component that looks readable over a calm gradient can fail over video, charts, product imagery, or dense dashboard panels. Use a surface tint and text shadow only when they improve readability without muddying the material. For dense data, prioritize legibility over dramatic translucency.

Treat hover, selected, disabled, danger, warning, and success states as separate dark-mode states. Disabled text should still be understandable, danger actions should not rely on red alone, and focus rings must be visible against both glass and the content behind it. Check command palettes, drawers, popovers, and modals because their elevation often changes perceived contrast.

#System Preference and Persistence

Use `prefers-color-scheme` as the default and let users override it when the product has account settings. Persist the explicit user choice, but avoid blocking first paint with a heavy theme script. A small inline bootstrap can set the initial attribute and prevent a flash between light and dark shells.

Dark mode should not change component semantics. A `GlassButton` remains a button, a `GlassDialog` remains a dialog, and a `GlassDataTable` remains a table or grid according to its API. Theme changes should tune presentation while preserving keyboard behavior, aria labels, SSR output, and hydration stability.

Default
Respect prefers-color-scheme
User choice
Persist an explicit light, dark, or system setting
Component API
Keep imports and props stable across themes
QA
Check contrast over real app backdrops, not only gradients