5.8 KiB
title, tags, created
| title | tags | created | |||
|---|---|---|---|---|---|
| Colors |
|
2026-05-23 |
Colors
The palette is built from semantic groups (primary, secondary, info, success, warning, error, plus a 9-step grey scale) and exposed via the MUI theme. Never hard-code hex values in components.
Warning
Hardcoded colors break dark mode and any future preset switch. Use
sx={{ color: 'primary.main' }}ortheme.palette.primary.main.
1. Semantic groups
Every color group has the shape:
{
lighter: '#…', // tint background, alerts
light: '#…', // hover surfaces, badges
main: '#…', // primary use (buttons, links)
dark: '#…', // hover state of `main`
darker: '#…', // pressed state
contrastText: '#…', // WCAG AA on `main`
}
1.1 Primary
| Token | Light hex (default preset) | Dark hex |
|---|---|---|
primary.lighter |
#D0ECFE |
#CCF4FE |
primary.light |
#73BAFB |
#68CDF9 |
primary.main |
#1877F2 |
#078DEE |
primary.dark |
#0C44AE |
#0351AB |
primary.darker |
#042174 |
#012972 |
primary.contrastText |
#FFFFFF |
#FFFFFF |
Used for primary actions, links, focused inputs.
1.2 Secondary
Typical: a complementary purple/teal. Confirm by reading theme/options/palette.ts.
1.3 Info / Success / Warning / Error
Standard semantic colors:
| Group | Hue | Used for |
|---|---|---|
info |
cyan/blue | Neutral informative banners |
success |
green | Confirmed payments, accepted offers |
warning |
amber | Pending state, mild alerts |
error |
red | Disputes, validation errors, destructive |
Each follows the same lighter/light/main/dark/darker/contrastText shape.
1.4 Grey
Nine-step scale (100 → 900). Use for:
grey.100–grey.300→ backgrounds, dividers, disabledgrey.500→ secondary text, muted iconsgrey.700–grey.900→ primary text, dark headings
1.5 Text & Background
text: {
primary: grey[800], // body
secondary: grey[600], // muted
disabled: grey[500],
},
background: {
default: '#FFFFFF', // light mode page
paper: '#FFFFFF', // cards, dialogs
neutral: grey[200], // page wash
},
In dark mode these invert (default becomes near-black, paper slightly lighter, text.primary near-white).
2. Action states
action: {
active: alpha(grey[600], 1),
hover: alpha(grey[500], 0.08),
selected: alpha(grey[500], 0.16),
disabled: alpha(grey[500], 0.8),
disabledBackground: alpha(grey[500], 0.24),
focus: alpha(grey[500], 0.24),
hoverOpacity: 0.08,
disabledOpacity: 0.48,
}
Use via sx={{ bgcolor: 'action.hover' }} etc.
3. Color presets
The settings drawer ships several color presets that swap only primary (and optionally secondary) while keeping every other group stable. Typical presets (confirm in theme/options/presets/):
| Preset | Primary hue | Vibe |
|---|---|---|
default |
Blue | Trust, finance |
purple |
Indigo/Purple | Premium |
cyan |
Cyan | Tech, fresh |
blue |
Vibrant blue | Strong CTA |
orange |
Orange | Energetic |
red |
Brand red | Bold |
To add a preset:
- Add a
<name>.tsfile intheme/options/presets/exporting{ lighter, light, main, dark, darker, contrastText }. - Register in the presets index map.
- Surface in the settings drawer color picker (
src/settings/drawer/).
4. Contrast verification
WCAG AA targets:
| Element | Min contrast |
|---|---|
| Body text (≥18 px regular or ≥14 px bold) | 4.5 : 1 |
| Large text (≥24 px regular or ≥18 px bold) | 3 : 1 |
| Icon-only buttons | 3 : 1 for their boundary |
| Form input borders | 3 : 1 |
Tip
When picking a new
maincolor, run it through Stark or the Chrome DevTools "Inspect color" checker againstbackground.paperANDbackground.defaultfor both light and dark modes.
5. Using colors in sx
// Token-based — preferred
<Box sx={{ bgcolor: 'primary.main', color: 'primary.contrastText' }} />
// Function form when you need to derive
<Box sx={(theme) => ({ bgcolor: alpha(theme.palette.primary.main, 0.08) })} />
// In styled component
const Item = styled('div')(({ theme }) => ({
background: theme.palette.background.paper,
color: theme.palette.text.primary,
}));
6. Charts & data viz
Use the helper theme.palette.<group>.main array for series colors. The chart/ component family (ApexCharts wrapper) reads these tokens so the chart palette stays in sync with the theme.
For categorical data with >7 series, layer in secondary.main, info.main, success.main, warning.main, error.main, then darker variants — never invent ad-hoc hex.
7. Diff visualisation (chat, evidence)
| Concept | Color token |
|---|---|
| Added / accepted | success.main with success.lighter background |
| Removed / rejected | error.main with error.lighter background |
| Pending review | warning.main |
| Informational | info.main |
8. Avatar backgrounds
MuiAvatar override hashes the user's name to one of the semantic main colors so the same person always gets the same background. Implementation in components/user-avatar/.
9. Brand vs semantic
| Use case | Token |
|---|---|
| Primary CTA button | primary.main |
| Success snackbar | success.main |
| Error border on form field | error.main |
| Page background | background.default |
| Card background | background.paper |
| Sidebar background | background.neutral |
| Divider line | divider |
| Primary text | text.primary |
| Muted helper text | text.secondary |
10. Related
- Theme Configuration · Design System Overview · Typography
- Components — components consuming these tokens
- Settings & Theming — preset switcher