Theme Modes and Tokens
Configure light/dark/system mode, token variables, and theme switch behavior in the current MuseMVP implementation.
This guide focuses on the current theme implementation in MuseMVP: mode switching (light / dark / system) plus CSS token customization.
Capability Overview
| Capability | Current behavior |
|---|---|
| Theme modes | Controlled by config.ui.enabledThemes |
| Default mode | Controlled by config.ui.defaultTheme |
| Theme provider | next-themes, mounted in src/modules/html-document/Document.tsx |
| Token source | src/app/globals.css and src/app/styles/theme.css |
| UI switcher | ColorThemeSwitcherNoCustomTheme used in app layouts |
Scope
The current system is a stable "mode switch + token variables" setup. It does not include a built-in multi-brand preset library.
Quick Configuration
Set allowed modes
Update enabledThemes and defaultTheme in src/config/index.ts.
// src/config/index.ts
ui: {
enabledThemes: ["light", "dark", "system"],
defaultTheme: "dark",
}Update core tokens
Update shared and dark-mode tokens in src/app/globals.css.
/* src/app/globals.css */
:root {
--background: oklch(...);
--foreground: oklch(...);
--primary: oklch(...);
}
.dark {
--background: oklch(...);
--foreground: oklch(...);
--primary: oklch(...);
}Add product-specific tokens when needed
Place additional design tokens in src/app/styles/theme.css (for example --success, --highlight) and consume them in components.
Mode Option Reference
| Mode | Meaning |
|---|---|
light | Always uses light palette |
dark | Always uses dark palette |
system | Follows OS/browser color-scheme preference |
Common Pitfalls
Import order matters
src/app/main.css imports theme.css first and globals.css second.
If the same variable exists in both files, globals.css wins.
Default mode must be enabled
Keep defaultTheme included in enabledThemes.
Example: if defaultTheme is dark, enabledThemes should still include dark.
Landing visual tokens
Default landing look is warm terracotta primary on a warm gray canvas, not a hard-edged theme.
| Token | Default | Where |
|---|---|---|
--radius | 0.875rem | src/app/globals.css (:root and .dark). @theme inline keeps the +4px radius ladder. |
--primary | terracotta / clay orange (oklch(0.55 0.14 42) in light) | src/app/globals.css |
| Shadows | soft multi-layer, not blur: 3px hard edges | src/app/globals.css |
.landing-grid | faint 72px grid with a radial mask | src/app/main.css |
Style-only rounded-none on landing cards is gone. Signed-in settings headers and panels (SettingsShell, SettingsPanelItem) use rounded-xl to match the shell. Keep rounded-none on control seams such as data-table, calendar, input-group, and toggle-group.
Related Docs
- App Layout Customization - Customize dashboard/admin layout style
- Application Configuration - Full
src/config/index.tsoptions - Internationalization - Theme label i18n mapping