web/src/themes/COLOR_GUIDE.md
This document explains the color system used in the Memos application, built with OKLCH color space for better perceptual uniformity and accessibility.
The color system supports both light and dark themes automatically through CSS custom properties. All colors are defined using OKLCH (Oklab LCH) color space, which provides better perceptual uniformity than traditional RGB/HSL.
| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--primary | Golden yellow | Brighter golden | Main brand color, primary CTAs |
--primary-foreground | White | White | Text on primary backgrounds |
When to use:
/* Example usage */
.cta-button {
background: var(--primary);
color: var(--primary-foreground);
}
| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--secondary | Light gray | Very light gray | Supporting actions |
--secondary-foreground | Dark gray | Dark gray | Text on secondary backgrounds |
When to use:
| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--background | Near white | Dark gray | Main page background |
--card | Near white | Dark gray | Card/container backgrounds |
--card-foreground | Very dark | Near white | Text on card backgrounds |
--popover | Pure white | Darker gray | Overlay backgrounds |
--popover-foreground | Dark gray | Light gray | Text on overlay backgrounds |
When to use:
--background)--card)--popover)| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--foreground | Dark gray | Light gray | Primary text color |
--muted | Light gray | Very dark | Subtle background areas |
--muted-foreground | Medium gray | Medium light | Secondary text, captions |
When to use:
--foreground)--muted-foreground)--muted)| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--accent | Light gray | Very dark | Hover states, selected items |
--accent-foreground | Dark gray | Light gray | Text on accent backgrounds |
--border | Medium light | Medium dark | Dividers, input borders |
--input | Medium light | Medium dark | Form input backgrounds |
When to use:
--accent)--border)--input)| Variable | Light Theme | Dark Theme | Usage |
|---|---|---|---|
--destructive | Very dark | Red | Error states, dangerous actions |
--destructive-foreground | White | White | Text on destructive backgrounds |
When to use:
| Variable | Purpose |
|---|---|
--chart-1 | Primary data series (golden) |
--chart-2 | Secondary data series (purple) |
--chart-3 | Tertiary data series (light) |
--chart-4 | Quaternary data series (purple variant) |
--chart-5 | Quinary data series (golden variant) |
When to use:
| Variable | Usage |
|---|---|
--sidebar | Sidebar background |
--sidebar-foreground | Sidebar text |
--sidebar-primary | Active sidebar items |
--sidebar-primary-foreground | Text on active sidebar items |
--sidebar-accent | Sidebar hover states |
--sidebar-accent-foreground | Text on sidebar hover states |
--sidebar-border | Sidebar dividers |
Always pair colors correctly:
/* Correct */
background: var(--primary);
color: var(--primary-foreground);
Use semantic meaning:
Respect the design system:
Don't mix incompatible pairs:
/* Incorrect - poor contrast */
background: var(--primary);
color: var(--foreground);
Don't use colors outside their intended purpose:
Don't hardcode color values:
/* Bad */
color: #333333;
/* Good */
color: var(--foreground);
The color system automatically adapts between light and dark themes when the .dark class is applied to a parent element (typically <html> or <body>):
// Toggle dark mode
document.documentElement.classList.toggle("dark");
/* Primary button */
.btn-primary {
background: var(--primary);
color: var(--primary-foreground);
border: 1px solid var(--primary);
}
/* Secondary button */
.btn-secondary {
background: var(--secondary);
color: var(--secondary-foreground);
border: 1px solid var(--border);
}
/* Destructive button */
.btn-destructive {
background: var(--destructive);
color: var(--destructive-foreground);
border: 1px solid var(--destructive);
}
/* Input field */
.input {
background: var(--input);
color: var(--foreground);
border: 1px solid var(--border);
}
/* Content card */
.card {
background: var(--card);
color: var(--card-foreground);
border: 1px solid var(--border);
}
/* Popover/Modal */
.popover {
background: var(--popover);
color: var(--popover-foreground);
box-shadow: var(--shadow-lg);
}
To ensure proper contrast and accessibility:
The application uses a structured z-index hierarchy to ensure proper layering of UI components:
| Component Type | Z-Index | Usage |
|---|---|---|
| Base Content | z-0 | Normal page content |
| Overlays | z-50 | Dialog/Sheet backgrounds |
| Modal Content | z-50 | Dialog/Sheet content |
| Dropdowns | z-[60] | Select, DropdownMenu, Popover content |
| Tooltips | z-[70] | Tooltip content (highest priority) |
z-50 for both overlay and contentz-[60] for dropdowns inside dialogsz-[70] to appear above all other elements// ✅ Correct: Select inside Dialog will appear above dialog content
<Dialog>
<DialogContent>
<Select>
<SelectContent className="z-[60]">
{" "}
<SelectItem>Option 1</SelectItem>
</SelectContent>
</Select>
</DialogContent>
</Dialog>
This color system is designed to provide a consistent, accessible, and beautiful user experience across all themes and components.