UIGuides

Color Theory for UI Designers: What Actually Matters

5 min read

Skip the art school theory. Learn the 60-30-10 rule, how to build a color scale, semantic color roles, WCAG contrast requirements, and accessible pairings for UI design.

Color theory as taught in art school covers things like simultaneous contrast, color temperature, and the color wheel. Most of it doesn't translate directly into building UI. What you actually need is a practical system for picking colors that look good, communicate clearly, and meet accessibility requirements.

Here's what matters.

The 60-30-10 rule for UI color

This rule gives you a reliable distribution of color across an interface:

  • 60% — your dominant neutral (backgrounds, surfaces, containers)
  • 30% — secondary color (sidebars, cards, secondary UI elements)
  • 10% — accent color (primary buttons, links, active states, key highlights)

Most UI design is neutral. The boldness of your brand shows up in that 10% accent. This is why cluttered, overwhelming interfaces usually have too much going on in the accent layer — every element fighting for attention.

Apply this to your design: if your background is white, your cards are light gray, and your primary button is blue, you're already following the rule. The moment you add a second accent color for decorative use, you start breaking it.

Building a color scale

Rather than choosing one blue and using it everywhere, you build a scale — typically 10 shades from near-white to near-black for each hue you need.

A standard scale uses these steps: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900. (Tailwind CSS popularized this convention and it's now widely used in design systems.)

To generate a scale:

  1. Pick your base color (usually the mid-range — 500 or 600)
  2. Create lighter variants by increasing lightness and decreasing saturation toward white
  3. Create darker variants by decreasing lightness and shifting saturation

Tools like Colorbox, Palettte, or the Figma plugin "Color Scales" can generate these automatically. You'll likely still need to tweak the generated values — automated scales often have perceptual inconsistencies.

For most products you need:

  • One brand/primary hue — your main accent color
  • One neutral scale — grays for backgrounds, surfaces, text
  • Semantic colors — red (error), green (success), yellow/orange (warning), blue (info — can reuse your primary)

That's typically four hue families. More than that and your palette gets hard to manage.

Semantic color roles

Named your colors gives you abstraction. Semantic color roles give you meaning. Map your scale values to roles:

Backgrounds and surfaces:

  • background — page background (white or gray-50)
  • surface — card/panel backgrounds (white or gray-100)
  • surface-raised — elevated elements like dropdowns (white with shadow)

Text:

  • text-primary — main body text (gray-900)
  • text-secondary — captions, labels, helper text (gray-600)
  • text-disabled — disabled form elements (gray-400)
  • text-inverse — text on dark backgrounds (white)

Interactive:

  • interactive-primary — primary button backgrounds, links (brand-600)
  • interactive-primary-hover — hover state (brand-700)
  • interactive-primary-disabled — (gray-300)

Feedback:

  • error — red-600
  • error-surface — red-50 (for alert backgrounds)
  • success — green-600
  • warning — yellow-500

Once you've named your colors this way, components reference the semantic name, not the raw value. This is the foundation of theming and dark mode support.

WCAG contrast requirements

WCAG 2.1 AA is the standard you should hit at minimum. Here's what it requires:

  • 4.5:1 contrast ratio for normal text (under 18pt regular, or 14pt bold)
  • 3:1 contrast ratio for large text (18pt regular or 14pt bold and above)
  • 3:1 contrast ratio for non-text UI elements (icons, input borders, chart elements)

WCAG AAA raises the text requirement to 7:1, which is appropriate for body copy on important pages but isn't required everywhere.

In practical terms:

  • Black text on white is 21:1 — always passes
  • Your gray-900 text on a white background will pass easily
  • Your secondary gray text (gray-500) on white might fail — check it
  • White text on your brand-600 color may or may not pass — you need to verify

Checking contrast in Figma with Stark

The Stark plugin for Figma lets you check contrast ratios directly in your designs without leaving the app. Select two layers or use the color picker to specify foreground and background colors, and Stark shows you the ratio and whether it passes AA or AAA.

Try Stark for Figma

Check contrast for:

  • Body text on every background color you use
  • Button labels on button backgrounds
  • Input placeholder text
  • Icon colors on their backgrounds
  • Focus ring colors against the surfaces they appear on

Don't just check your default state. Check hover states, disabled states, and error states too.

Accessible color pairings that work

Some pairings that reliably pass AA:

  • gray-900 on white: 21:1
  • white on gray-700: 5.7:1
  • white on brand-700 (dark shade of your primary): usually passes — verify
  • gray-700 on gray-50: typically passes — verify with your specific values

Some common failures:

  • Gray-500 on white: often fails (around 3.9:1)
  • Yellow text on white: almost always fails
  • Light blue on white: often fails for body text sizes
  • Any pastel on white: likely fails

The fix is almost always to use a darker foreground color. If you want light gray for secondary text, go darker — gray-700 instead of gray-500.

Try Figma Free

Build contrast checking into your process, not as an afterthought. Run Stark on every new component before you hand it off. Fixing a color at the component stage takes 30 seconds. Fixing it after engineering has implemented it takes a day.