<?xml version="1.0" encoding="utf-8"?>

Color shapes how an interface feels long before users read a single word. When a palette is structured well, it becomes easier to stay consistent, communicate hierarchy, and support accessibility across an entire product. Clear roles for each color help teams avoid guesswork and keep visual decisions aligned, even as the system grows.

Tonal ranges bring stability to a palette by creating predictable steps from light to dark. These ranges can be built with simple, hands-on methods that give designers full control instead of relying only on automated tools. Modern features like variables in Figma then make it possible to turn these colors into organized, reusable assets that fit naturally into everyday workflows.

A reliable color system becomes a shared language. It supports smoother collaboration, reduces unnecessary variation, and makes product decisions easier to maintain over time.

Exercise #1

Understanding accent color roles

Understanding accent color roles

Accent colors in a system gain meaning through the roles they carry. Material Design 3 divides these roles into primary, secondary, and tertiary, each supporting a different level of emphasis in the interface:

  • Primary accent roles support the most important actions. They include 4 values: the primary color, the on-primary color for text and icons placed on it, the primary container, and the on-primary container. These roles help highlight key elements such as a prominent action button or an active state.
  • Secondary accent roles support elements that still need visibility but not strong emphasis. They also consist of 4 values that describe how fills and text pair within this quieter role. These roles are used for components like filter chips or tonal buttons.
  • Tertiary accent roles introduce complementary accents. They bring additional contrast when a design needs a distinct visual cue without relying on the primary or secondary colors. Their four values help apply these accents consistently across fills, text, icons, and containers.[1]

Exercise #2

Defining primary colors through interface analysis

Another way to define primary colors for a color system is to look directly at the product interface. Instead of starting from predefined roles, teams begin by collecting all colors currently used across the UI. This review highlights which colors appear most often and which ones support important interactions. These recurring colors form the foundation of the primary palette because they already shape how the product looks and behaves.

This approach often reveals patterns that are not obvious at first glance. It helps identify the main brand color, the shades most commonly used for surfaces, and the specific hues that support key functions like success, warning, or error states. Colors that appear consistently across many components are added to the primary set so the design system represents the product as it is, not as a theoretical ideal. This prevents the palette from introducing unrelated colors and makes future updates smoother.

Once this primary set is established, each color is checked against the existing interface. If the UI contains similar colors that serve the same purpose, they can be merged or replaced with the defined primary values. This reduces visual noise caused by near-duplicates and creates a cleaner base for expanding the rest of the system. This method also supports accessibility work, since a stable, well-defined primary palette makes it easier to test contrast and maintain clarity across components.[2]

Pro Tip: When reviewing the UI, pay attention to colors used for feedback. These often define your functional palette long before you formalize it.

Exercise #3

Identifying secondary and tertiary colors through product usage

Secondary and tertiary colors can be defined by looking at how a product already uses color across its interface. A color inventory helps reveal which hues appear often enough to deserve a place in the system, even if they are not part of the primary brand set. For example, many interfaces rely on multiple shades of gray, quieter highlight colors, or supporting tones that give structure to layouts and components. These colors may not carry the same weight as the primary palette, but they still shape the product and need clear representation in the system.

This inventory also exposes colors that appear only in a few places but still play a meaningful role. A subtle background tint, a supporting highlight, or a color used in specific UI modules can become part of a tertiary group. Defining these colors prevents the system from accumulating one-off shades, which often happen when designers recreate slightly different versions of the same hue. Merging similar values into a single defined color helps keep the expanded palette clean and manageable.

Once secondary and tertiary candidates are identified, the remaining UI should be checked for near-duplicates or irrelevant colors. Any color that does not serve a specific purpose can be replaced with a defined secondary or tertiary value.[3]

Pro Tip: Group similar colors during your audit. Families of near-identical shades often reveal the natural starting point for secondary and tertiary palettes.

Exercise #4

Defining functional colors through UI needs

Defining functional colors through UI needs

Functional colors come from the product’s real feedback requirements. During an interface audit, some hues appear repeatedly in states like errors, warnings, or confirmations. These colors should be documented as part of the system because they already carry meaning in the UI.

A typical audit reveals several similar shades used for the same function. Instead of keeping them all, teams select one reliable value and replace near-duplicates. This reduces noise and prevents slightly different reds or greens from appearing across new screens. After selecting the main functional colors, they should be checked against common backgrounds to make sure text or icons remain readable.

Pro Tip: When merging similar functional colors, keep the one that appears most consistently in important UI states.

Exercise #5

Creating a structured surface palette

Surface colors come from the neutral tones already used throughout the product. An audit usually reveals a small group of grays used repeatedly in backgrounds, containers, and layout sections. These recurring colors form the base of the surface palette because they already support the interface visually. One-off neutrals or barely used tones can be merged with these stable values to avoid inconsistent backgrounds.

Once the main neutrals are identified, they can be assigned simple roles, such as primary background, secondary background, or container. Even small shifts between these tones help create hierarchy without introducing new colors. Keeping the surface palette structured this way makes layouts more predictable and reduces the number of decisions designers need to make.

Pro Tip: If two neutrals look nearly identical, merge them. Subtle differences rarely serve a meaningful purpose.

Exercise #6

Creating a tonal scale using opacity

Creating a tonal scale using opacity

After defining the key primary colors, the next step is to build the tones that sit above and below them. These tones can be chosen by personal preference or created through a more controlled process. A tonal scale makes the palette easier to use because every shade stays connected to the original color. Tonal palettes also help keep the interface balanced and accessible.

To create lighter tones:

  • Start with the base color, for example gray 500.
  • Draw a rectangle filled with this color and lower its opacity to around 80%.
  • Duplicate the rectangle and use the color picker to sample the new visible color. This becomes gray 400.
  • Repeat the process by lowering opacity further, such as to 60%, and sample again to create gray 300.

Saving each sampled tone as its own value keeps the scale consistent.

For darker tones, place the base color rectangle on a black or very dark background. Adjust the opacity until the color looks slightly deeper. Once the shade feels right for the next step, use the color picker to sample it and save that color as gray 600. Continue this process for darker values, such as gray 700. Each sample becomes a stable color in the palette instead of relying on live opacity changes.

Exercise #7

Using plugins to generate tonal scales

Using plugins to generate tonal scales

Figma plugins can speed up the process of building tonal scales when you need to create many steps quickly. Plugins like UI Color Palette, Color Shades, Foundation Colour Generator, and Tailwind CSS Color Generator generate lighter and darker tones from a single base color in a few clicks. They let you preview full ranges of tints and shades, which helps compare several variations before choosing the ones that fit the palette best.

Even when plugins help generate the first draft, the final tones still need manual review. Comparing plugin-generated values with your opacity-based samples ensures the chosen colors stay consistent with the rest of the palette and remain readable across different surfaces. Plugins help with speed and exploration, while manual checks keep the palette controlled and accurate.

Pro Tip: Use plugins to explore options quickly, then refine the final tones through sampling to keep the palette coherent.

Exercise #8

Naming colors and keeping structure clear

Naming colors and keeping structure clear Bad Practice
Naming colors and keeping structure clear Best Practice

Naming conventions help teams understand each color’s purpose at a glance. Here are widely used methods:

  • Functional naming, where colors are labeled based on what they represent, such as base-blue, base-gray, or base-red. This approach highlights which values act as the core colors in the system.
  • Numeric naming, where numbers show variations of a color, like silver-1 or silver-darken-15. These scales make it easier to add or adjust tones without guessing their relationship to the base value.
  • Combined naming. For example, a palette might use blue-base, blue-100, blue-200, and blue-300 to show a clear family structure while also giving each tone a defined place on the scale. This mix keeps names easy to read while still supporting expansion.

Whatever the chosen approach, the key is consistency. When every color follows the same pattern, the palette becomes easier to navigate, update, and use across both design and development.

Pro Tip: Make sure your naming pattern works for future tones, not just the ones you have now.

Exercise #9

Creating and managing color variables in Figma

Creating and managing color variables in Figma

Color variables in Figma turn your color system into a stable, reusable part of the design system. Instead of applying hex codes manually, each palette color becomes a single variable that can be used across components. Updating the variable updates every element that relies on it, which keeps the color system consistent across screens and states.

To open the Variables panel, make sure no layer is selected on the canvas. Then look at the right sidebar and click the icon with two sliders next to the word “Variables.” This expands the panel where you can create and manage all color values.

Click Create variable, choose Color, and give the variable a clear name. Use Collections to group related variables, such as “Brand,” “Functional,” or “Surfaces.” Collections help keep the palette organized and make the system easier to maintain as it grows.

To connect variables, open a color variable, click the color field, and select Alias. This links the variable to another base value so changes cascade through the system. Collections also support Modes, such as “Light” and “Dark,” allowing the same variable to hold different values depending on the theme.[4]

Pro Tip: Use short, structured names like brand/blue-500 or surface/200. It keeps variables easy to scan when you work fast.

Exercise #10

Handling edge cases and functional conflicts

Handling edge cases and functional conflicts

Some products have brand colors that conflict with functional meanings. Imagine the brand color is #FF4A4A, a bright red. If this shade is close to the error color used in the UI, users may confuse branding with feedback. Instead of adjusting the brand color, introduce a dedicated error color family that stays visually distinct. For example, define error colors starting at #D32F2F, then build lighter or darker variations from it for containers or states. This keeps functional messages clear while preserving the brand’s identity.

Some interfaces also rely on colors that appear rarely, such as lines in charts or data segments. If the product uses such colors, for example, for graphs, create a small “Data Colors” group instead of letting these values exist as one-offs. This controlled set can include three to five colors that support visualizations without expanding the main palette.

Exercise #11

Checking color accessibility

Checking color accessibility

After defining your palette, every color pair used for text, icons, and surfaces should be checked for contrast. Contrast testing ensures readability and meets accessibility standards. You can check contrast using tools like WebAIM Contrast Checker, Figma’s built-in contrast checker, or browser extensions that test color pairs directly. These tools confirm whether the combination meets recommended contrast ratios for normal and large text.

To make future work easier, create a small list of approved color pairs that always pass accessibility checks. Store this list in your design system documentation so designers do not need to test the same combinations repeatedly. When new colors are added to the palette later, test them against your main surface and text colors and add any passing pairs to the same reference. This keeps the accessibility workflow simple even as the palette grows.[5]

Complete lesson quiz to progress toward your course certificate