How to Build a Color System for Your Design: A Developer Guide
Learn how to create a consistent, accessible color system for your web application — from choosing a base color to generating a full palette with tints, shades, and semantic colors.
Why You Need a Color System
A color system ensures visual consistency across your entire application. Without one, you end up with dozens of slightly different grays, blues, and greens scattered across your CSS — making maintenance a nightmare and accessibility impossible to verify.
Step 1: Choose Your Base Colors
Every color system starts with a few base colors:
- Primary — Your brand color, used for buttons, links, and key actions
- Neutral — Grays for text, borders, and backgrounds
- Success — Green for positive states
- Warning — Yellow/orange for caution
- Error — Red for errors and destructive actions
Use our Color Picker to explore colors, or our Color Palette Generator to find harmonious combinations.
Step 2: Generate a Scale
For each base color, generate a scale of 10 shades from light to dark:
:root {
--blue-50: #eff6ff;
--blue-100: #dbeafe;
--blue-200: #bfdbfe;
--blue-300: #93c5fd;
--blue-400: #60a5fa;
--blue-500: #3b82f6; /* Base */
--blue-600: #2563eb;
--blue-700: #1d4ed8;
--blue-800: #1e40af;
--blue-900: #1e3a8a;
--blue-950: #172554;
}
Use our Color Shades Generator to create these scales from any base color.
Step 3: Define Semantic Tokens
Map your color scale to semantic purposes:
:root {
/* Text */
--text-primary: var(--gray-900);
--text-secondary: var(--gray-600);
--text-muted: var(--gray-400);
/* Backgrounds */
--bg-primary: #ffffff;
--bg-secondary: var(--gray-50);
--bg-tertiary: var(--gray-100);
/* Borders */
--border-primary: var(--gray-200);
--border-secondary: var(--gray-300);
/* Interactive */
--accent: var(--blue-600);
--accent-hover: var(--blue-700);
--accent-muted: var(--blue-50);
}
Step 4: Ensure Accessibility
Every text/background combination must meet WCAG contrast requirements:
- Normal text: 4.5:1 minimum (AA)
- Large text: 3:1 minimum (AA)
- Enhanced: 7:1 (AAA)
Use our Color Contrast Checker to verify every combination.
Common mistakes:
- Gray text on white background often fails (need at least #767676 for AA)
- Colored text on colored backgrounds (check both light and dark modes)
- Placeholder text that's too light to read
Step 5: Dark Mode
For dark mode, don't just invert colors. Create a separate set of tokens:
.dark {
--text-primary: var(--gray-100);
--text-secondary: var(--gray-400);
--bg-primary: var(--gray-950);
--bg-secondary: var(--gray-900);
--border-primary: var(--gray-800);
--accent: var(--blue-400); /* Lighter in dark mode */
}
Step 6: Implement in CSS
/* Use semantic tokens everywhere */
.button {
background: var(--accent);
color: white;
}
.button:hover {
background: var(--accent-hover);
}
.card {
background: var(--bg-primary);
border: 1px solid var(--border-primary);
color: var(--text-primary);
}
/* Never use raw color values in components */
/* ❌ Bad */
.card { border-color: #e5e7eb; }
/* ✅ Good */
.card { border-color: var(--border-primary); }
Related Tools
- Color Palette Generator — Generate harmonious palettes
- Color Shades Generator — Create tint/shade scales
- Color Contrast Checker — Verify WCAG compliance
- Color Converter — Convert between HEX, RGB, HSL, CMYK
- Color Picker — Pick and explore colors
- Tailwind Color Finder — Find Tailwind equivalents
- CSS Gradient Generator — Create gradient backgrounds