Design CraftColor

Color in UI design: what you actually need to know

Most UI color problems aren't about choosing colors. They're about using too many of them, for the wrong reasons.

The question designers spend the most time on, which colors to pick, is usually not the most important one. The harder question is what each color is supposed to do, and whether the system has enough discipline to make that consistent over time.

Most UI color systems fail because they grow. A brand blue gets used for primary actions. Then a secondary button needs to be different, so a lighter blue gets added. A warning state needs amber, then a success state needs green. The new feature has a promotional badge, so someone picks an orange that feels energetic. Two years later the system has 14 colors and nobody knows which ones are semantic (meaning something about state) versus decorative (filling space).

Semantic color is the load-bearing structure

Semantic colors are the ones that carry meaning: the red that signals error, the green that signals success, the yellow that signals warning, the blue that signals information or default interaction. These are the colors your users are already trained to interpret from every other interface they use. Your job is not to subvert those conventions but to apply them consistently.

The failure mode is using a semantic color for a non-semantic purpose. If your primary brand color is red, and you use it for buttons, headings, and decorative accents as well as error states, users will occasionally misread an active button as an error message. The visual system can't communicate both "this is interactive" and "something is wrong" with the same signal.

The fix is to separate the semantic palette from the brand palette. Your brand red might influence the exact shade of your error red so they feel like relatives, but they should be distinct tokens with distinct purposes.

Neutrals do more work than color

In most well-designed interfaces, 80% of the surface area is neutral: backgrounds, cards, dividers, text. Color appears as a signal, not a wallpaper. The neutrals define the base, and color punctuates it.

A neutral scale that's underdeveloped produces flat, undifferentiated UI. If your neutral palette has only two values (white and a medium gray), you have no visual hierarchy between the page background, card surfaces, borders, disabled states, and secondary text. These all need to be distinct, and they need to be distinct in a way that reads as intentional, not just as different grays that happened to get used.

A useful neutral scale has at minimum six to eight values: one for page background, one for elevated surfaces, one or two for borders, and three or four for text at different hierarchy levels. More than that and the palette becomes hard to use consistently. Less than that and the visual language runs out of tools.

Color tokens aren't just named hex values

The distinction between a raw hex value and a token is that a token carries intent. #1a73e8 is a color. color.action.primary is a decision. The token name tells you what the color is for, which means anyone using the token knows whether they're using it correctly.

Systems that name tokens by their appearance (blue-500, red-300) are better than raw hex values but still leave the intent ambiguous. Is blue-500 for interactive elements, for informational callouts, or for decorative accents? A primitive like blue-500 can't answer that question. A semantic token like action.default can.

The practical benefit is change management. If your primary interactive color needs to change from one blue to another (a brand refresh, an accessibility fix, a dark mode requirement), a semantic token lets you make that change in one place. A codebase that uses raw hex values or even named primitives requires a search-and-replace across every file that touches color, with no guarantee you found every instance.

Where color carries meaning vs. where it carries noise

Color is most useful when it's doing something that shape, position, and text cannot do alone. An error icon next to an input field communicates something visually. The red border on the input field communicates the same thing with color, giving users two signals instead of one. That redundancy is intentional: color alone is an accessibility violation.

Color carries noise when it's applied without a purpose. A card grid where cards cycle through four colors communicates nothing about the card content unless those colors mean something: category, status, priority. If they don't mean anything, they're visual noise that the user's eye has to process and dismiss. The four-color card grid that represents four project types is doing work. The four-color card grid where the colors were chosen for visual variety is not.

The question to ask for every deliberate color choice is: if I removed this color and replaced it with the neutral version, what information would the user lose? If the answer is nothing, the color isn't carrying meaning. It's decoration. Decoration isn't wrong, but it should be used with restraint, and it should lose every argument it has with semantic color.

How color systems break down over time

The most common way a color system degrades is through local decisions. A designer working on a new feature needs a color that isn't in the system. They pick one. They use it. Nobody notices because it's in one component on one screen. Six months later it's been used in four other components, each with slightly different values, because subsequent designers saw it in an earlier component and didn't have a reference for the exact token.

The second most common failure is token proliferation without governance. Every time a one-off case generates a new token like badge-promotional-orange or sidebar-hover-bg-subtle-warm, the system grows in complexity without growing in clarity. New tokens that aren't needed systemically should instead be handled as hardcoded exceptions with a comment explaining why they don't belong in the system.

Audit frequency matters. A color audit, comparing what's in the token system against what's actually in use in the codebase, surfaces drift before it becomes entrenched. The longer the gap between audits, the more expensive the cleanup.

The restraint principle

Restraint in color use is often mistaken for conservatism or lack of creativity. It's neither. It's a recognition that color's communicative power comes from contrast: a signal is only visible against a quiet background.

A UI that uses color purposefully and sparingly will always communicate more clearly than one that uses color freely. The card that glows amber has meaning only if amber is rare. The red badge on the notification icon demands attention only if red doesn't appear for any other reason. Use color to direct attention, not to fill space.


A useful proxy for whether a color system is working: ask someone new to the codebase to implement a new component from a screenshot. If they reach for the right tokens without needing to look them up, the system is communicating. If they open the Figma file, pick colors by eye, and hardcode hex values, the system hasn't done its job.

Greg Sargent
Greg SargentDirector of Design Systems, Spring Health

I write about design systems, accessibility, and the way AI is changing how we build software.

Published March 2, 2026

Be the first to rate this article.