208 lines
5.8 KiB
Markdown
208 lines
5.8 KiB
Markdown
---
|
||
title: Colors
|
||
tags: [design-system, colors, palette]
|
||
created: 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' }}` or `theme.palette.primary.main`.
|
||
|
||
---
|
||
|
||
## 1. Semantic groups
|
||
|
||
Every color group has the shape:
|
||
|
||
```ts
|
||
{
|
||
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, disabled
|
||
- `grey.500` → secondary text, muted icons
|
||
- `grey.700`–`grey.900` → primary text, dark headings
|
||
|
||
### 1.5 Text & Background
|
||
|
||
```ts
|
||
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
|
||
|
||
```ts
|
||
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:
|
||
|
||
1. Add a `<name>.ts` file in `theme/options/presets/` exporting `{ lighter, light, main, dark, darker, contrastText }`.
|
||
2. Register in the presets index map.
|
||
3. 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 `main` color, run it through [Stark](https://stark.co/) or the Chrome DevTools "Inspect color" checker against `background.paper` AND `background.default` for both light and dark modes.
|
||
|
||
---
|
||
|
||
## 5. Using colors in `sx`
|
||
|
||
```tsx
|
||
// 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
|