Frontend Theming (MUI)
Refract’s admin UI uses a token-based theming setup: raw design tokens inthemeConstants, mode selection in theme.ts, and ThemeProvider wiring in layouts.
How it works
If you keep the flow in your head, theming becomes straightforward.1) Tokens: raw values for light/dark
All color/typography/spacing values come from:apps/portal/src/components/hooks/themeConstants.ts
2) Mode selection: useAdminTheme
apps/portal/src/components/hooks/theme.ts selects light/dark using:
- localStorage key
themeMode - system preference
(prefers-color-scheme: dark) - cross-tab sync via the
storageevent
3) Layout wiring: ThemeProvider in layouts
The admin layout wraps page content with the chosen theme (seeapps/portal/src/pages/admin/layout/index.tsx).
Pattern:
Extending this system
Use this recipe to change theme tokens without breaking the light/dark mode behavior.- Update the tokens you want to change in
apps/portal/src/components/hooks/themeConstants.ts.
PRIMARY_MAIN:
-
Keep mode selection logic in
apps/portal/src/components/hooks/theme.ts(don’t duplicate it). -
Use the updated theme values via MUI’s
sxand palette semantics instead of hardcoding.
- Verify:
What not to do
These are the guardrails that keep theming centralized and predictable. ❌ Never hardcode a palette color in multiple components when the token should live inthemeConstants.
❌ Never add a new ThemeProvider just to style one page; it will drift from the shared mode logic.
❌ Never remove CssBaseline behavior in apps/portal/src/main.tsx.
File conventions
Use these locations and naming patterns so new theme code stays easy to find. Prefer:- semantic palette usage (like
background.paper,text.primary) sxfor local styling that still uses theme semantics
