Accessible color palette for light and dark mode in Figma
Build an accessible color palette that meets WCAG AA in light and dark mode: the contrast ratios, the color pairs to test, and the Figma tools that check or adjust them.
An accessible color palette isn't a list of colors that "pass". It's a set of color pairs that pass: text on its background, a button label on the button, an input border on the surface around it. Under WCAG 2.2 level AA, text needs a contrast ratio of at least 4.5:1, large text 3:1, and the visual parts that identify a control 3:1. In a light and dark setup, every pair has to pass in both modes, which usually means picking different steps for dark mode rather than inverting the scale.
This guide covers the ratios, the specific pairs to test, how to build the palette in Figma so the pairs are easy to check, and the tools that check contrast or suggest fixes.
The three numbers
From the W3C's explanations of WCAG 2.2:
- 4.5:1 for normal text against its background (1.4.3 Contrast (Minimum)).
- 3:1 for large text, which WCAG defines as 18 point, or 14 point bold.
- 3:1 for the visual information people need to identify a control and its state, such as an input's border when the border is what shows it's an input, a checkbox's check, or a focus indicator (1.4.11 Non-text Contrast).
Two exceptions save a lot of arguing. Disabled controls have no contrast requirement, and neither do logos. The W3C also says the thresholds aren't rounded: 2.999:1 doesn't meet 3:1.
The pairs to test
A palette has dozens of colors but only a handful of pairs that matter. For each mode, test:
| Pair | Minimum (AA) |
|---|---|
| Primary text on page background | 4.5:1 |
| Primary text on raised surfaces (cards, modals) | 4.5:1 |
| Secondary text on page and raised surfaces | 4.5:1 |
| Button label on each button color | 4.5:1 (3:1 if large) |
| Link text on page background | 4.5:1 |
| Input border on the surface around it | 3:1 |
| Focus ring on the surface around it | 3:1 |
| Status text (error, success, warning) on its background | 4.5:1 |
| Icons without a text label | 3:1 |
Secondary text on raised surfaces and warning colors (yellow and amber) are where palettes fail most often. In dark mode, borders are the usual problem: a border that looks fine at a glance may be well under 3:1, and only matters when it's the thing that shows where an input is.
Why dark mode needs its own steps
The same step can pass on white and fail on near-black, because contrast depends on the luminance of both colors. Three habits help:
- Pick text and accent steps per mode. An accent that passes on white at the 600 step often needs the 400 or 300 step on a dark surface.
- Flip the label color when you flip the button. A light accent in dark mode may need dark text on it, not white.
- Check raised surfaces, not just the page. Dark mode cards are lighter than the page, so text on cards has less contrast than text on the page.
If you work in Tailwind, our Tailwind dark mode color palette guide has a starting map of steps.
Building the palette in Figma so it's testable
Set the palette up as variables in two layers:
- Primitives: one collection with full scales for each color family, a single mode.
- Semantic roles: a second collection with Light and Dark modes, where
text/secondary,surface/raised,border/inputand the rest alias a primitive step in each mode. Our variable modes setup guide covers this, and modes need a paid Figma plan.
Then build a simple test frame: one row per pair from the table, using the semantic variables, and duplicate it with the Dark mode applied. When you change an alias, the test frame shows the result in both modes at once.
Tools that check contrast
Figma's built-in check. The color picker has a contrast view: select a layer, open its fill, and Figma shows the ratio between that color (always treated as the foreground) and the background, with AA and AAA indicators. You can set the category (normal text, large text, graphics), and clicking a failing indicator moves the value to the nearest color that passes (Figma). For checking individual pairs, it's often all you need.
Plugins add palette-wide views. Numbers below are from each Figma Community listing on October 25, 2026.
- Color contrast checker WCAG 2.1 (44,648 users) checks one foreground against one background. Simple, and its listing was last updated in November 2024.
- UI Color Palette (96,286 users) builds palettes in perceptual color spaces such as OKLCH and LCH, shows WCAG 2.1 and APCA scores for each shade, and builds light, dark and color-blindness modes. Its pricing page lists a free basic tier with limits (3 palettes per document, 2 color modes) and a pro tier at $2.99 per user per week on weekly billing, with monthly, yearly and lifetime options also listed. Pro adds what it calls advanced accessibility tools.
- Supa Palette (105,810 users) generates palettes with light and dark modes and includes a contrast grid in WCAG or APCA plus automatic contrast suggestions, per its site. The site offers a one-week trial; it's a paid plugin after that.
Adjusting colors automatically
Some tools go a step further and change colors to reach a target:
- Figma's color picker can move a failing color to the nearest passing one, one fill at a time.
- Supa Palette describes smart contrast suggestions that find colors to keep a design accessible.
- Huekit is our plugin, and on paid plans it adjusts the semantic color tokens it generates toward WCAG AA targets automatically, as described on huekit.io. That works on the token layer, so the adjusted values apply wherever those tokens are used. See huekit.io for what each plan includes.
Whatever adjusts the color, look at the result. A value that technically passes can lose its brand character or flatten the hierarchy between primary and secondary text. Treat automatic adjustment as a starting point for the pairs you review, not a replacement for that review.
WCAG 2 or APCA?
WCAG 2.2's contrast ratio is the current standard and what audits and legal requirements reference. APCA is a newer method that predicts perceived contrast and takes font size and weight into account; it was developed for the draft WCAG 3, which isn't final. In practice: design to WCAG 2.2 AA so you meet today's requirement, and if a tool also shows APCA, use it as a second opinion on thin or small text, where the WCAG 2 ratio can be generous.
Tools at a glance
| Tool | What it does for contrast | Light/Dark | Pricing (as published) |
|---|---|---|---|
| Figma color picker | Checks a pair, can move a fill to a passing color | Per frame mode | Included in Figma |
| Color contrast checker WCAG 2.1 | Checks one pair | No | No paid tier listed |
| UI Color Palette | WCAG 2.1 and APCA scores per shade | Yes | Free basic; pro $2.99/user/week (weekly billing) |
| Supa Palette | Contrast grid (WCAG or APCA), suggestions | Yes | Trial, then paid |
| Huekit | Adjusts semantic tokens toward WCAG AA | Yes | See huekit.io |
Links: Supa Palette site.
FAQ
What contrast ratio does WCAG AA require for text?
4.5:1 for normal text and 3:1 for large text (18 point, or 14 point bold).
Do borders and icons need to meet contrast requirements?
Yes, when they're needed to identify a control or understand content. WCAG 2.2 asks for 3:1 against adjacent colors, for example an input's border or an icon button without a label.
Do disabled buttons need to meet contrast?
No. WCAG exempts inactive components from the contrast requirements.
How do I check color contrast in Figma?
Open a layer's fill in the color picker and use the contrast view. Figma shows the ratio against the background and whether it meets AA or AAA.
Can a palette pass in light mode and fail in dark mode?
Yes. Contrast depends on both colors, so the same step can pass on white and fail on a dark surface. Test each pair in both modes.
Should I use APCA instead of WCAG?
Use WCAG 2.2 AA as the requirement. APCA is useful as a second opinion, but it's part of the draft WCAG 3, not the current standard.
Start with your secondary text
Find your secondary text color, put it on your raised surface in both modes, and check the ratio in Figma's color picker. If it passes in both, the rest of the palette usually needs only small fixes.
About the author
Written by the Huekit team.
Want the fast path?
Huekit builds the color scales, semantic tokens, and Light/Dark modes inside your Figma file, then exports JSON tokens or a Tailwind config.
Get Huekit on FigmaKeep reading
Catppuccin, Dracula and Tokyo Night in Figma: turn an editor theme into variables
Map Catppuccin, Dracula, Tokyo Night or One Dark onto Figma variables with Light and Dark modes: which flavor goes where, which roles to create, and which pairs fail contrast.
How to export Figma variables to Tailwind (v4 @theme or v3 config)
Three ways to export Figma variables to Tailwind: native JSON export plus a build step, an export plugin, or a generator with export built in. With v4 CSS for light and dark.
How to create a design system in Figma from scratch (startup size)
Build a small design system in Figma from scratch: color variables, text styles, spacing and radius, ten core components, a docs page and a library, with plan limits noted.