A color palette is the complete set of colors your product uses. A well-structured palette covers every need — branding, interactive states, backgrounds, text, borders, errors, and successes — while remaining manageable and consistent. This lesson walks through building a production-ready palette from scratch.
Palette Structure
A web application palette typically includes these categories:
Primary Color
Your brand's main color. It appears on primary buttons, active navigation items, links, and key UI accents. You need the base shade plus lighter and darker variants for hover states, backgrounds, and borders.
Secondary Color
A complementary or supporting color for secondary actions and less prominent UI elements. Not every product needs one — some designs work beautifully with a single primary color plus neutrals.
Accent Color
An optional high-contrast color for drawing attention to specific elements — badges, notifications, or promotional banners.
Neutral Scale
The most used colors in your palette. Neutrals cover backgrounds, text, borders, dividers, and disabled states. You typically need 8 to 10 shades from near-white to near-black.
Semantic Colors
Colors tied to meaning: error (red), success (green), warning (yellow/amber), and info (blue). These are functional, not decorative.
Generating a Full Scale
Start with your primary color and generate a 10-step scale from lightest (50) to darkest (900). Here is a blue primary scale:
:root {
--primary-50: #eff6ff;
--primary-100: #dbeafe;
--primary-200: #bfdbfe;
--primary-300: #93c5fd;
--primary-400: #60a5fa;
--primary-500: #3b82f6; /* Base */
--primary-600: #2563eb;
--primary-700: #1d4ed8;
--primary-800: #1e40af;
--primary-900: #1e3a8a;
}The key principle: lighter shades decrease saturation and increase lightness, while darker shades increase saturation slightly and decrease lightness. Do not just add white or black — that creates muddy, lifeless colors.
Building a Neutral Scale
Pure gray (equal R, G, B) often feels cold and lifeless. Most design systems tint their neutrals slightly toward the primary color for cohesion:
:root {
/* Neutrals tinted slightly toward blue */
--neutral-50: #f8fafc;
--neutral-100: #f1f5f9;
--neutral-200: #e2e8f0;
--neutral-300: #cbd5e1;
--neutral-400: #94a3b8;
--neutral-500: #64748b;
--neutral-600: #475569;
--neutral-700: #334155;
--neutral-800: #1e293b;
--neutral-900: #0f172a;
}Use these neutrals for text (neutral-900 for headings, neutral-600 for body, neutral-400 for placeholder text), backgrounds (neutral-50, neutral-100), and borders (neutral-200, neutral-300).
Semantic Color Scales
Semantic colors need at least three values: a light background, the base color, and dark text that is readable on the light background:
:root {
/* Error */
--error-bg: #fef2f2;
--error: #dc2626;
--error-text: #991b1b;
/* Success */
--success-bg: #f0fdf4;
--success: #16a34a;
--success-text: #166534;
/* Warning */
--warning-bg: #fffbeb;
--warning: #d97706;
--warning-text: #92400e;
/* Info */
--info-bg: #eff6ff;
--info: #2563eb;
--info-text: #1e40af;
}These triples let you build alert banners, form validation messages, and status indicators with proper contrast.
Tools for Palette Generation
| Tool | What It Does | URL |
|---|---|---|
| Realtime Colors | Preview your palette on a realistic website layout | realtimecolors.com |
| Coolors | Generate and explore harmonious palettes | coolors.co |
| Tailwind CSS Colors | A battle-tested set of color scales | tailwindcss.com/docs/colors |
| HSL Color Picker | Fine-tune individual colors with HSL sliders | hslpicker.com |
| Contrast Checker | Verify text-to-background contrast ratios | webaim.org/resources/contrastchecker |
Dark Mode Palettes
Dark mode is not just inverting your light palette. Effective dark mode requires:
- Elevated surfaces instead of shadows — In dark mode, lighter surfaces feel "closer." Use
neutral-800for cards on aneutral-900background. - Reduced saturation — Vivid colors that look great on white can feel harsh on dark backgrounds. Reduce saturation by 10-20%.
- Proper text contrast — Use
neutral-100orneutral-200for body text on dark backgrounds, not pure white (#ffffff), which causes eye strain.
.dark {
--color-background: var(--neutral-900);
--color-surface: var(--neutral-800);
--color-text: var(--neutral-100);
--color-text-secondary: var(--neutral-400);
--color-primary: #60a5fa; /* Lighter, less saturated blue */
}Common Mistakes
- Too many colors — If your palette has 40+ named colors, it is too complex to use consistently. Aim for a primary scale, neutrals, and semantics.
- Ignoring contrast — A beautiful color is useless if text on top of it is unreadable. Always check contrast ratios.
- Forgetting interactive states — Every color used on an interactive element needs hover, active, focus, and disabled variants.
- Pure black backgrounds —
#000000as a background is harsh. Use a very dark neutral like#0f172ainstead.