# Design: Add Dark Mode
## Technical Approach
Use CSS custom properties (CSS variables) for all color values, toggled via a React Context. The theme toggle updates a `data-theme` attribute on the root element, which triggers CSS variable swaps. Theme preference is persisted to `localStorage`.
This approach maps to the proposal's recommended "CSS Variables + React Context" pattern and satisfies all spec requirements.
## Architecture Decisions
### Decision: CSS Variables vs. CSS-in-JS
**Choice**: CSS custom properties (CSS variables)
**Alternatives considered**: Styled Components with ThemeProvider
**Rationale**:
- No runtime overhead — CSS is static
- No need to refactor existing CSS files to JS
- Better performance (no JS in style computation)
- Existing codebase already uses plain CSS
- Easier for designers to modify themes (just change variables, not JS objects)
### Decision: Context vs. Redux for Theme State
**Choice**: React Context
**Alternatives considered**: Add theme to Redux store
**Rationale**:
- Theme is UI-only state (not business logic)
- Doesn't need time-travel debugging
- Simpler — no action creators, no reducers
- Avoids coupling theme to application state
### Decision: localStorage Key and Format
**Choice**: Store as `theme: "light" | "dark"` string in localStorage
**Alternatives considered**: Store as boolean `isDark`, or complex object with more settings
**Rationale**:
- String enum is extensible (can add more themes later)
- Simpler to read/debug than boolean
- No need for complex object in MVP
## Data Flow
User clicks toggle
│
v
ThemeContext.toggleTheme()
│
├──→ Update state
├──→ Write to localStorage
└──→ Set data-theme attribute on <html>
│
v
CSS :root[data-theme="dark"] activates
│
v
UI re-renders with new colors
## File Changes
| File | Action | Description |
|------|--------|-------------|
| `src/contexts/ThemeContext.tsx` | Create | Theme state and toggle logic, provides theme to components |
| `src/hooks/useTheme.ts` | Create | Hook to consume theme context, returns `{ theme, toggleTheme }` |
| `src/styles/theme.css` | Modify | Convert hardcoded colors to CSS variables, add dark palette |
| `src/components/App.tsx` | Modify | Wrap app with `<ThemeProvider>` |
| `src/components/Header.tsx` | Modify | Add theme toggle button (moon/sun icon) |
| `src/main.tsx` | Modify | Add inline script to apply theme before first render (avoid flash) |
## Interfaces / Contracts
### ThemeContext Interface
```typescript
type Theme = 'light' | 'dark';
interface ThemeContextValue {
theme: Theme;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);