Here’s a Figma hack I’ve been using to help me rapidly determine if a given color token has enough contrast to be accessible on dark mode and light mode backgrounds. I’ve run into the problem when working in a new design system where I haven’t yet memorized which color tokens are accessible on which backgrounds. Plugins like Stark partly solve the problem but take time—if I remember to use them at all.
This hack probably won’t apply to everyone, though. This is only useful if your design system uses a full-spectrum palette with many color options that fall outside the range of accessible contrast ratios, or if you haven’t already memorized all the accessible color combinations.
The Problem This Solves
To meet WCAG AA contrast requirements, your text needs to be at least 4.5:1. It can be 3:1 if it’s either 18.66px and bold, or 24px.
In a perfect world, you’ll have a simpler color palette to work with where contrast ratios have already been figured out. However, that’s not always realistic. For instance, my team uses Tailwind CSS, which I love.
The problem is that Tailwind’s many color options aren’t always consistently accessible at the same level. For instance,
gray500 meets both 3:1 and 4.5:1 contrast requirements. However
purple500 only meets 3:1 requirements, and
green500 meets neither.
In order to visualize which colors I could use, I started by mapping out which colors met requirements on both dark mode and light mode backgrounds. I did this quickly with the Stark plugin and the “run last plugin” shortcut in Figma (
cmd + alt + p).
While this was useful, it still took a lot of time to hunt for the right color I needed.
This isn’t terribly elegant, but here’s a solution that works for me.
When naming my color styles, I append the
— symbol for dark backgrounds, and the
+ symbol for light backgrounds. Here are the rules:
- If a color is at least 3:1 on a dark background, it gets a
- If a color is at least 3:1 on a light background, it gets a
- If a color is at least 4.5:1 on a dark background, it gets
- If a color is at least 4.5:1 on a light background, it gets
- If a color meets multiple levels, multiple symbols can be combined. For instances, a purple that is at least 3:1 on a dark background and 4.5:1 on a light background would be named
purple600++-. A gray that is the first level to meet both 3:1 and 4.5:1 on light backgrounds would be named
The reason this works is that when picking colors on the fly, I can easily tell which has enough contrast and which will fail an accessibility check. Here’s an example of this in action.
I had a few ideas to overengineer this hack, which is an instinct I try to resist whenever possible. So I’ll leave them here for you in case you want to go ham.
- Multiple symbols for multiple backgrounds ¢∞§¶•!@#$%^&*)
You could use other symbols to show contrast requirements for many backgrounds if that’s a thing you need to worry about.
- Emoji symbols ☀️☀️🌙🌙
These would probably be easier to understand on the fly, especially with lots of designers on the team. I opted for
-for ease of typing.
- Labeling every color
I only labeled the threshold colors. For instance
500+++(to show that it’s the first instance of a gray that is both 3:1 and 4.5:1), however,
gray600has no special symbols since it’s implied given 600 is a darker variant of the same color.
I hope this helps. Please leave a comment if there are any other ideas or plugins I haven’t heard about that solve this problem.