Design · Opinion

How to Choose an Accessible Color Palette for Your Next Project

I want to tell you about a client's father.

It was 2017, my second year at a Brooklyn e-commerce agency. We were auditing a direct-to-consumer skincare brand's checkout flow because their conversion rate was bad and nobody could figure out why. The funnel looked clean. The copy was good. The product photography was excellent. But the primary CTA on the payment page was a pale dusty-pink button on a near-white background, and our user testing kept turning up the same thing: people would sit on that screen for fifteen, twenty seconds before clicking anything. Some of them never clicked at all.

The founder of the brand happened to mention, almost in passing during a status call, that her father had stopped using the site. He had age-related macular degeneration. He was their target demographic — older skin, premium positioning, gift-buying for his wife — and he literally could not see the button. When I ran the contrast through a checker, it came back at 1.4:1. The WCAG minimum is 4.5:1 for normal text and 3:1 for "large" UI elements. Our button was below the minimum for anything.

We changed the button color. Conversion went up 23% in two weeks. I have been an accessibility person ever since.

The thing I want you to take away from this story is not "use better contrast." The thing I want you to take away is that color accessibility is conversion work, brand work, and ethics work all at once, and most designers I meet still treat it like a checklist they grudgingly check at the end. This post is for those designers. (Honestly, it is also a little bit for past me.)

What "accessible" actually means for color

Let's get a few definitions out of the way, because the conversation gets sloppy otherwise.

Accessibility for color is mostly about three populations whose needs overlap but are not identical:

  • People with low vision. This includes age-related conditions like macular degeneration, glaucoma, cataracts, and diabetic retinopathy, plus congenital low vision. These users need high contrast, period.
  • People with color vision deficiency (CVD). About 8% of men and 0.5% of women of Northern European descent have some form of red-green CVD; the global rate is lower but still meaningful. They need information to never be encoded by color alone.
  • People using your interface in adverse conditions. Sunlight on a phone screen, an old projector, a cheap monitor, a dimmed display in a meeting. Bad contrast hurts these users too. Accessibility benefits spill outward.

WCAG (the Web Content Accessibility Guidelines) is the standard most of the industry uses. Version 2.1 AA is the minimum I would ship anything at; 2.2 AA is current and where I aim. The relevant rules for color are 1.4.3 Contrast (Minimum), 1.4.11 Non-text Contrast, and 1.4.1 Use of Color. We will cover what each one wants in plain English.

"Color accessibility is conversion work, brand work, and ethics work all at once, and most designers I meet still treat it like a checklist they grudgingly check at the end."

The three-bucket palette method

This is the system I have used on every project for the last six years. It is not novel — most mature design systems converge on something like it — but I have rarely seen it spelled out cleanly for someone starting from scratch. So here it is.

You are not building one palette. You are building three, and they have different jobs.

Bucket 1: Neutrals (the structure)

This is your text colors, your backgrounds, your borders, your dividers. It is the largest bucket by surface area on screen and the one most people get wrong. You need at least eight steps from your lightest neutral (background) to your darkest (primary text), and they need to be tuned so that several of them pass 4.5:1 against your background and 3:1 for UI elements.

My quick rule: pick your background and your primary text first, verify they hit at least 7:1 (that is WCAG AAA, and it costs you nothing to aim there for body text), then build the intermediate steps so that secondary text hits 4.5:1, tertiary text hits 4.5:1 on common surfaces, and borders/dividers hit 3:1 where they need to convey structure. If a divider is purely decorative, you can drop it lower, but be honest about which is which.

One frequent mistake: using pure black (#000000) for primary text on pure white (#FFFFFF). The contrast is technically fine — it is 21:1, the maximum possible — but it creates eye strain over long reading sessions and looks visually harsh. I almost always nudge primary text to something like #111827 or #1F2937 and the background to #FAFAFA or off-white. You give up about 2 points of contrast and gain a more comfortable reading experience.

Bucket 2: Brand (the personality)

This is your one or two signature hues. The thing the brand is "about." Pink, teal, forest green, whatever your stakeholders fought about for six weeks.

Here is the trick: your brand color almost never needs to pass 4.5:1 contrast itself. It needs to pass contrast in the specific roles where it will carry text or convey meaning. So the question is not "is my brand color accessible?" The question is "what shades of my brand color do I need to derive so that the use cases I care about pass?"

Build a ramp from your brand hue — typically 9 or 10 steps, from a near-white tint to a near-black shade. For a typical hue, you will end up with one step around the middle that is your "true" brand color (used for backgrounds, accents, illustrations) and one step toward the dark end that is contrast-safe for use as a button background with white text (usually around step 600-700 in a Tailwind-style ramp). When you need brand-colored text on a white background, you reach for a step 700 or 800 variant, not the original hue.

This is the single most-asked-about thing in design system reviews I do. Designers want to put their brand color on a button with white text and it fails contrast at 3.2:1, and they think they have to pick a new brand color. They do not. They have to pick a darker variant of the same hue, for that specific use.

Color Palette Generator

Building a ramp from a single brand color by eye is hard and inconsistent. Use the palette generator to produce evenly-stepped tints and shades, then check contrast on the ones you plan to use for text or interactive elements.

Open Color Palette Generator →

Bucket 3: Status (the meaning)

Success green, warning yellow, error red, info blue. The four (or sometimes five) colors that carry semantic meaning across your interface. These are the most regulated colors in your palette because they are also the most common failure point for color vision deficiency.

Three rules I never break for status colors:

  1. Never use red and green as the only difference between two states. Always pair color with an icon, a label, or both. "The graph line that goes up is green and the one that goes down is red" is a famous CVD failure pattern. Add up and down arrows. Bold the values. Whatever you have to do.
  2. Make the status colors distinct on the luminance axis, not just the hue axis. Your error red should be perceptibly darker or lighter than your warning yellow when viewed in grayscale. Convert your palette to grayscale and look at it. If two status colors look identical in grayscale, they look identical to a meaningful portion of your users.
  3. Verify each status color passes contrast in every role it plays. Error red on a white background needs to hit 4.5:1 if it is carrying text. The little red dot on a notification badge needs to hit 3:1. The error background fill behind a text input does not need to pass on its own, but the text inside it does.

Color Blindness Simulator

Run your palette through deuteranopia, protanopia, and tritanopia simulations. If your success and error colors merge under any of them, you have a problem and you need either a different hue or — better — a non-color signal layered on top.

Open Color Blindness Simulator →

The contrast math, in plain English

WCAG 2 contrast is calculated using the formula (L1 + 0.05) / (L2 + 0.05) where L1 and L2 are the relative luminance of the two colors. The formula has known weaknesses — it is not perceptually uniform, it is too lenient on dark backgrounds, and it is being replaced in WCAG 3 by APCA — but it is the standard, and you should know what the thresholds mean.

  • 4.5:1 — minimum for normal text (AA)
  • 3:1 — minimum for "large" text (18pt+ or 14pt+ bold), and for UI components and graphical objects
  • 7:1 — enhanced minimum for normal text (AAA)
  • 4.5:1 — enhanced minimum for large text (AAA)

What "passes" looks like in practice: take your body text color and your background color, plug them into a contrast checker, and you should see at least 4.5:1. For headings (typically larger and bolder), 3:1 is technically enough but I aim for 4.5:1 anyway because it costs nothing. For placeholder text in form inputs, you need at least 4.5:1 — this is one of the most common WCAG violations on production sites because designers use a light gray to "look subtle" and it lands at 3:1 or below.

What about dark mode?

The math is the same — you just flip which is L1 and which is L2 — but humans perceive contrast slightly differently on dark backgrounds. A pure white text on pure black background tests at 21:1 and is fine on paper, but it can produce a "halation" effect where the text appears to vibrate against the background, especially for astigmatic users. I almost always tune dark mode primary text to something like #F5F5F5 or #E5E7EB, against a background of #0F172A or #111827. Slightly lower contrast on paper, much more comfortable on screen.

Gradients are a trap

I want to talk about this specifically because I see it constantly. Gradients are beautiful and popular and they have a real accessibility problem: they have no single contrast value. The background under any given letter of your white text might be light pink at the top and deep indigo at the bottom, and the contrast varies wildly across the surface.

Two rules:

  1. If you are putting text over a gradient, check contrast against the lightest point AND the darkest point. Both must pass for the text color you are using. Usually this means picking a text color and a gradient whose stops both work, or adding a semi-transparent overlay that flattens the contrast variation.
  2. If your gradient is decorative — purely background, no text on top — you have more freedom, but be honest about whether anyone will ever try to put text there. Stakeholders love asking for "just one line of overlay text" two months after launch.

Gradient Generator

Generate CSS gradients with controllable color stops, then test the lightest and darkest points against your intended text color before committing.

Open Gradient Generator →

A practical workflow

Here is the order I follow on a new project. Adapt it; do not worship it.

  1. Define the background-text pair first. What is the primary text color on the primary background? Verify it hits 7:1 if you can. This anchors everything else.
  2. Build the neutral ramp. Eight or so steps from your background to your primary text, with intermediate steps that you can verify against the background for secondary text (4.5:1) and dividers (3:1).
  3. Add the brand color and derive its ramp. Find the variant that works as a button background with white text. Find the variant that works as brand-colored text on a light background. Document both.
  4. Add status colors and verify in CVD simulation. Each status color needs to pass contrast in its actual uses AND remain distinguishable under deuteranopia and protanopia.
  5. Test in dark mode. Run the whole exercise again with inverted backgrounds. You will find at least one color that does not work and needs a separate dark-mode variant.
  6. Convert to HEX and document. Every color in the palette should be expressible as a HEX value with a documented role. If you cannot describe the role in one sentence, you have too many colors.

HEX/RGB Converter

Move between HEX, RGB, and HSL representations cleanly. Useful when you are translating between a designer's color picker (often HSL or LAB) and a developer's CSS file (almost always HEX or RGB).

Open HEX/RGB Converter →

Common mistakes I still see in 2026

Treating accessibility as a phase-two project

You will not retrofit your way to accessibility. Color palettes built without contrast awareness almost always need to be redone, not patched. Build it in from the start; it is cheaper and the result is better-looking.

Trusting your monitor

Your $1,800 calibrated display is not a reasonable testing surface. Pull the design up on your phone in direct sunlight. Pull it up on an old IPS panel in a meeting room. Pull it up on your grandparent's iPad mini. If it falls apart in any of those contexts, the palette is too aggressive.

Letting brand color override role

If your brand color is "hot magenta" and the stakeholder wants the primary CTA in hot magenta and white, and the contrast is 2.8:1 — the CTA cannot be that color. It is a usability failure. Find the darker variant of magenta that works. The stakeholder gets the brand expression; the user gets to actually use the button. Everybody wins.

Forgetting placeholder and disabled states

Disabled buttons are allowed to fail contrast — they are exempt from WCAG by design. But placeholder text in inputs is NOT exempt and needs to hit 4.5:1. This is one of the most common violations on otherwise-accessible sites. Check your placeholders.

Using color as the only error indicator

Red border around a form field that failed validation is not enough. Add an icon. Add a message. Make the message announce itself to screen readers. Color is a reinforcement, never the sole signal.

What I would do this week if I were starting from scratch

Open a blank Figma file, or whatever your tool is. Pick a background color and a primary text color. Verify they hit at least 7:1. Build a neutral ramp from one to the other. Pick a brand hue. Generate a 10-step ramp from that hue. Verify which step works as a button background with white text. Pick three status hues. Verify each one passes contrast AND looks distinct under deuteranopia simulation. Document every color with its hex value and its role.

You can do all of that in an afternoon. You will save weeks of remediation later.

Start your accessible palette

Generate the ramps, test the contrast, simulate color vision deficiency, and convert between formats — all from the same set of free tools. The palette work itself is craft; the verification is just plumbing.

Open Color Palette Generator →

Toolrip Editorial Team is CPACC-certified (IAAP, 2019) and a Web Accessibility Specialist (IAAP, 2022). She consults on accessibility remediation and design systems. This article reflects her practice, not legal compliance advice — for ADA or EAA conformance specific to your jurisdiction, consult an accessibility lawyer or audit firm.