OKLCH Studio · Accessible palettes · Product & UI
Accessible color palette for landing pages (WCAG 2.2 verified)
Updated 2026-10-19
A landing page has one goal, and its colour is built around it: a button that stands out. Marketing teams want loud colour and big type, which often leads to white text on bright orange or pastel buttons on a pale gradient. Those choices look striking in a mock-up and fail on a phone in daylight. A landing page also tends to be the first thing a visitor sees, so a failure here is the most public.
The sections of a landing page each need their own check: hero headline over a coloured band, feature cards, testimonials, pricing tables and the footer call to action. This palette verifies the roles that cover them: text on the page and card colours, a primary button with its label, accent text and a border for pricing cards.
WCAG 2.2 AA is the standard most marketing sites are measured against. Headlines are held at AAA, and large text only needs 3:1 under WCAG, so there is room to be bold without risk.
How to build a palette like this by hand is explained in the accessible colour palette guide; this page is the finished, verified result.
The palette: light and dark
Hex values are the sRGB result after gamut mapping. The oklch() values are those of the final hex, so converting either gives the same colour.
Appointment confirmed
Secondary text sits on the surface colour.
Link in primary · Accent text
Light theme
- Background
#FCFCFC
oklch(0.991 0.000 0.0)
Sample text
- Surface
#FEFEFE
oklch(0.997 0.000 0.0)
Sample text
- Text
#1B1B1B
oklch(0.222 0.000 0.0)
Sample text
- Muted text
#585858
oklch(0.460 0.000 0.0)
Sample text
- Primary
#9827A0
oklch(0.501 0.200 325.1)
Sample text
- Primary foreground
#FCFCFC
oklch(0.991 0.000 0.0)
Sample text
- Accent
#8A6200
oklch(0.5242 0.1084 80.64)
Sample text
- Border
#919191
oklch(0.657 0.000 0.0)
Sample text
- Focus ring
#871090
oklch(0.449 0.200 324.8)
Sample text
- Success
#00845A
oklch(0.5422 0.1184 162.29)
Sample text
- Success fill
#008558
oklch(0.545 0.122 160.9)
Sample text
- Success fill label
#FCFCFC
oklch(0.991 0.000 0.0)
Sample text
- Warning
#A46600
oklch(0.5651 0.1234 68.77)
Sample text
- Warning fill
#FFBA44
oklch(0.8335 0.1508 76.88)
Sample text
- Warning fill label
#0F0F0F
oklch(0.168 0.000 0.0)
Sample text
- Error
#A21A1B
oklch(0.4603 0.1706 26.95)
Sample text
- Error fill
#C8322E
oklch(0.551 0.187 27.1)
Sample text
- Error fill label
#FCFCFC
oklch(0.991 0.000 0.0)
Sample text
- Info
#2274AF
oklch(0.540 0.120 245.0)
Sample text
- Info fill
#1377B9
oklch(0.5501 0.1324 245.13)
Sample text
- Info fill label
#FCFCFC
oklch(0.991 0.000 0.0)
Sample text
Appointment confirmed
Secondary text sits on the surface colour.
Link in primary · Accent text
Dark theme
- Background
#161616
oklch(0.200 0.000 0.0)
Sample text
- Surface
#202020
oklch(0.244 0.000 0.0)
Sample text
- Text
#EEEEEE
oklch(0.949 0.000 0.0)
Sample text
- Muted text
#BEBEBE
oklch(0.802 0.000 0.0)
Sample text
- Primary
#FC8BFF
oklch(0.798 0.195 326.3)
Sample text
- Primary foreground
#0D0D0D
oklch(0.159 0.000 0.0)
Sample text
- Accent
#EABF3A
oklch(0.8207 0.1502 90.01)
Sample text
- Border
#6B6B6B
oklch(0.528 0.000 0.0)
Sample text
- Focus ring
#FC8BFF
oklch(0.798 0.195 326.3)
Sample text
- Success
#6CE5B5
oklch(0.839 0.130 164.9)
Sample text
- Success fill
#3BCD9A
oklch(0.759 0.143 165.0)
Sample text
- Success fill label
#0F0F0F
oklch(0.168 0.000 0.0)
Sample text
- Warning
#FFBC56
oklch(0.839 0.140 75.1)
Sample text
- Warning fill
#E9A11D
oklch(0.7605 0.1539 75.30)
Sample text
- Warning fill label
#0F0F0F
oklch(0.168 0.000 0.0)
Sample text
- Error
#F66D62
oklch(0.700 0.171 27.0)
Sample text
- Error fill
#FF7A6D
oklch(0.732 0.165 27.5)
Sample text
- Error fill label
#0F0F0F
oklch(0.168 0.000 0.0)
Sample text
- Info
#71BFFF
oklch(0.780 0.120 245.0)
Sample text
- Info fill
#61B9FF
oklch(0.760 0.132 244.8)
Sample text
- Info fill label
#0F0F0F
oklch(0.168 0.000 0.0)
Sample text
Contrast table: every verified pair
Pass or fail uses the raw WCAG 2.x ratio; the ratio shown is floored to two decimals so a near miss is never rounded up. APCA Lc is signed: positive is dark on light, negative is light on dark. Each row opens the pair in the checker.
| Pair | WCAG ratio | Target | Normal AA / AAA | Large AA / AAA | APCA Lc | APCA tier | Check |
|---|---|---|---|---|---|---|---|
| Text on background#1b1b1b on #fcfcfc | 16.78:1 | AAA 7:1 | Pass / Pass | Pass / Pass | +102.3 | Lc 75: body text | Open in checker |
| Text on surface#1b1b1b on #fefefe | 17.07:1 | AAA 7:1 | Pass / Pass | Pass / Pass | +103.5 | Lc 75: body text | Open in checker |
| Muted text on background#585858 on #fcfcfc | 6.93:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +82.9 | Lc 75: body text | Open in checker |
| Muted text on surface#585858 on #fefefe | 7.05:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +84.1 | Lc 75: body text | Open in checker |
| Primary as link text on background#9827a0 on #fcfcfc | 6.53:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +80.1 | Lc 75: body text | Open in checker |
| Primary as link text on surface#9827a0 on #fefefe | 6.64:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +81.3 | Lc 75: body text | Open in checker |
| Button label on primary#fcfcfc on #9827a0 | 6.53:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −85.0 | Lc 75: body text | Open in checker |
| Accent text on background#8a6200 on #fcfcfc | 5.34:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +75.3 | Lc 75: body text | Open in checker |
| Accent text on surface#8a6200 on #fefefe | 5.43:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +76.5 | Lc 75: body text | Open in checker |
| Border on background#919191 on #fcfcfc | 3.07:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +56.8 | Lc 45: headlines and large text | Open in checker |
| Border on surface#919191 on #fefefe | 3.12:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +58.0 | Lc 45: headlines and large text | Open in checker |
| Focus ring on background#871090 on #fcfcfc | 8.16:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +85.4 | Lc 75: body text | Open in checker |
| Focus ring on surface#871090 on #fefefe | 8.30:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +86.6 | Lc 75: body text | Open in checker |
| Success text on background#00845a on #fcfcfc | 4.60:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +70.4 | Lc 60: larger content text | Open in checker |
| Success text on surface#00845a on #fefefe | 4.68:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +71.6 | Lc 60: larger content text | Open in checker |
| Success badge label on fill#fcfcfc on #008558 | 4.55:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −75.3 | Lc 75: body text | Open in checker |
| Warning text on background#a46600 on #fcfcfc | 4.56:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +70.4 | Lc 60: larger content text | Open in checker |
| Warning text on surface#a46600 on #fefefe | 4.64:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +71.6 | Lc 60: larger content text | Open in checker |
| Warning badge label on fill#0f0f0f on #ffba44 | 11.28:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +73.2 | Lc 60: larger content text | Open in checker |
| Error text on background#a21a1b on #fcfcfc | 7.58:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +83.5 | Lc 75: body text | Open in checker |
| Error text on surface#a21a1b on #fefefe | 7.71:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +84.7 | Lc 75: body text | Open in checker |
| Error badge label on fill#fcfcfc on #c8322e | 5.17:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −78.4 | Lc 75: body text | Open in checker |
| Info text on background#2274af on #fcfcfc | 4.89:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +72.5 | Lc 60: larger content text | Open in checker |
| Info text on surface#2274af on #fefefe | 4.97:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +73.7 | Lc 60: larger content text | Open in checker |
| Info badge label on fill#fcfcfc on #1377b9 | 4.68:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −76.3 | Lc 75: body text | Open in checker |
| Pair | WCAG ratio | Target | Normal AA / AAA | Large AA / AAA | APCA Lc | APCA tier | Check |
|---|---|---|---|---|---|---|---|
| Text on background#eeeeee on #161616 | 15.59:1 | AAA 7:1 | Pass / Pass | Pass / Pass | −95.8 | Lc 75: body text | Open in checker |
| Text on surface#eeeeee on #202020 | 14.04:1 | AAA 7:1 | Pass / Pass | Pass / Pass | −94.6 | Lc 75: body text | Open in checker |
| Muted text on background#bebebe on #161616 | 9.73:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −66.5 | Lc 60: larger content text | Open in checker |
| Muted text on surface#bebebe on #202020 | 8.76:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −65.3 | Lc 60: larger content text | Open in checker |
| Primary as link text on background#fc8bff on #161616 | 8.85:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −62.0 | Lc 60: larger content text | Open in checker |
| Primary as link text on surface#fc8bff on #202020 | 7.97:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −60.8 | Lc 60: larger content text | Open in checker |
| Button label on primary#0d0d0d on #fc8bff | 9.51:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +64.2 | Lc 60: larger content text | Open in checker |
| Accent text on background#eabf3a on #161616 | 10.35:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −70.1 | Lc 60: larger content text | Open in checker |
| Accent text on surface#eabf3a on #202020 | 9.31:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −68.9 | Lc 60: larger content text | Open in checker |
| Border on background#6b6b6b on #161616 | 3.39:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | −24.3 | Below Lc 30 | Open in checker |
| Border on surface#6b6b6b on #202020 | 3.05:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | −23.1 | Below Lc 30 | Open in checker |
| Focus ring on background#fc8bff on #161616 | 8.85:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −62.0 | Lc 60: larger content text | Open in checker |
| Focus ring on surface#fc8bff on #202020 | 7.97:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −60.8 | Lc 60: larger content text | Open in checker |
| Success text on background#6ce5b5 on #161616 | 11.64:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −77.0 | Lc 75: body text | Open in checker |
| Success text on surface#6ce5b5 on #202020 | 10.48:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −75.8 | Lc 75: body text | Open in checker |
| Success badge label on fill#0f0f0f on #3bcd9a | 9.47:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +64.6 | Lc 60: larger content text | Open in checker |
| Warning text on background#ffbc56 on #161616 | 10.84:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −72.7 | Lc 60: larger content text | Open in checker |
| Warning text on surface#ffbc56 on #202020 | 9.76:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −71.5 | Lc 60: larger content text | Open in checker |
| Warning badge label on fill#0f0f0f on #e9a11d | 8.74:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +60.6 | Lc 60: larger content text | Open in checker |
| Error text on background#f66d62 on #161616 | 6.27:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −46.5 | Lc 45: headlines and large text | Open in checker |
| Error text on surface#f66d62 on #202020 | 5.65:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | −45.3 | Lc 45: headlines and large text | Open in checker |
| Error badge label on fill#0f0f0f on #ff7a6d | 7.53:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +54.2 | Lc 45: headlines and large text | Open in checker |
| Info text on background#71bfff on #161616 | 9.13:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −63.4 | Lc 60: larger content text | Open in checker |
| Info text on surface#71bfff on #202020 | 8.22:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −62.2 | Lc 60: larger content text | Open in checker |
| Info badge label on fill#0f0f0f on #61b9ff | 9.02:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +62.1 | Lc 60: larger content text | Open in checker |
Status colours and colour blindness
The four status fills were simulated for protanopia, deuteranopia and tritanopia (Machado et al., 2009). Success against error, the pair most often confused, must stay at least 6 ΔE-OK ×100 apart under every simulation. The other pairs are shown for information, so keep an icon and a word on every status.
| Pair | Normal vision | Protanopia | Deuteranopia | Tritanopia | Held to 6 |
|---|---|---|---|---|---|
| success / warning | 34.2 | 26.0 | 39.0 | 31.7 | Shown only |
| success / error | 28.5 | 16.6 | 6.5 | 33.0 | Yes |
| success / info | 17.1 | 16.2 | 15.2 | 3.2 | Shown only |
| warning / error | 31.8 | 42.0 | 37.4 | 22.6 | Shown only |
| warning / info | 40.0 | 34.2 | 44.5 | 31.2 | Shown only |
| error / info | 30.3 | 24.1 | 21.6 | 33.0 | Shown only |
Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia
| Pair | Normal vision | Protanopia | Deuteranopia | Tritanopia | Held to 6 |
|---|---|---|---|---|---|
| success / warning | 20.9 | 11.8 | 15.5 | 27.5 | Shown only |
| success / error | 28.8 | 15.3 | 6.4 | 31.3 | Yes |
| success / info | 17.7 | 15.2 | 14.3 | 3.8 | Shown only |
| warning / error | 13.3 | 13.2 | 10.5 | 5.5 | Shown only |
| warning / info | 28.5 | 26.0 | 28.7 | 26.2 | Shown only |
| error / info | 28.3 | 21.8 | 20.8 | 29.7 | Shown only |
Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia
Why these colours
The primary is a magenta at OKLCH hue 325 with chroma 0.20, the highest primary chroma among the business palettes here. At the AA lightness needed for white button labels it is a deep, rich fuchsia, which stands out strongly against white. The accent is yellow at hue 90, the opposite of magenta-violet on the wheel.
Yellow has the highest lightness of any hue and cannot be used for text on white; the solved accent text colour is a dark gold. In practice, use yellow as a highlight block behind dark text, like a marker pen on the headline, and that pair is verified through the warning badge. Neutrals are true greys so the colour is carried by the two brand hues.
The generator solved 50 pairs (25 light, 25 dark), and all of them meet their target on the raw WCAG ratio. The tightest is success badge label on fill in the light theme at 4.55:1 against a target of 4.5:1. After gamut mapping to sRGB the light primary keeps 100% of the requested chroma; hue was held throughout.
How to use it
- Make the main button the primary colour with the verified label and put no other filled button of that colour nearby.
- Use a yellow highlight behind dark text for emphasis, not yellow text on white.
- Keep gradients behind headlines subtle and test their lightest and darkest points against the text colour.
- Pricing tables: mark the recommended plan with a border and a label, not just a colour change.
- Check your cookie banner and chat widget; third-party overlays often introduce their own low-contrast colours.
Export
Generated from the verified values above, never typed by hand. Light and dark are both included.
CSS custom properties (hex, then oklch())
/* sRGB hex first: every browser. */
:root {
--color-background: #fcfcfc;
--color-surface: #fefefe;
--color-text: #1b1b1b;
--color-text-muted: #585858;
--color-primary: #9827a0;
--color-primary-foreground: #fcfcfc;
--color-accent: #8a6200;
--color-border: #919191;
--color-focus-ring: #871090;
--color-success: #00845a;
--color-success-solid: #008558;
--color-success-solid-foreground: #fcfcfc;
--color-warning: #a46600;
--color-warning-solid: #ffba44;
--color-warning-solid-foreground: #0f0f0f;
--color-error: #a21a1b;
--color-error-solid: #c8322e;
--color-error-solid-foreground: #fcfcfc;
--color-info: #2274af;
--color-info-solid: #1377b9;
--color-info-solid-foreground: #fcfcfc;
}
.dark {
--color-background: #161616;
--color-surface: #202020;
--color-text: #eeeeee;
--color-text-muted: #bebebe;
--color-primary: #fc8bff;
--color-primary-foreground: #0d0d0d;
--color-accent: #eabf3a;
--color-border: #6b6b6b;
--color-focus-ring: #fc8bff;
--color-success: #6ce5b5;
--color-success-solid: #3bcd9a;
--color-success-solid-foreground: #0f0f0f;
--color-warning: #ffbc56;
--color-warning-solid: #e9a11d;
--color-warning-solid-foreground: #0f0f0f;
--color-error: #f66d62;
--color-error-solid: #ff7a6d;
--color-error-solid-foreground: #0f0f0f;
--color-info: #71bfff;
--color-info-solid: #61b9ff;
--color-info-solid-foreground: #0f0f0f;
}
/* oklch() where supported: the same colours, unclipped values of the hex above. */
@supports (color: oklch(0 0 0)) {
:root {
--color-background: oklch(0.991 0.000 0.0);
--color-surface: oklch(0.997 0.000 0.0);
--color-text: oklch(0.222 0.000 0.0);
--color-text-muted: oklch(0.460 0.000 0.0);
--color-primary: oklch(0.501 0.200 325.1);
--color-primary-foreground: oklch(0.991 0.000 0.0);
--color-accent: oklch(0.5242 0.1084 80.64);
--color-border: oklch(0.657 0.000 0.0);
--color-focus-ring: oklch(0.449 0.200 324.8);
--color-success: oklch(0.5422 0.1184 162.29);
--color-success-solid: oklch(0.545 0.122 160.9);
--color-success-solid-foreground: oklch(0.991 0.000 0.0);
--color-warning: oklch(0.5651 0.1234 68.77);
--color-warning-solid: oklch(0.8335 0.1508 76.88);
--color-warning-solid-foreground: oklch(0.168 0.000 0.0);
--color-error: oklch(0.4603 0.1706 26.95);
--color-error-solid: oklch(0.551 0.187 27.1);
--color-error-solid-foreground: oklch(0.991 0.000 0.0);
--color-info: oklch(0.540 0.120 245.0);
--color-info-solid: oklch(0.5501 0.1324 245.13);
--color-info-solid-foreground: oklch(0.991 0.000 0.0);
}
.dark {
--color-background: oklch(0.200 0.000 0.0);
--color-surface: oklch(0.244 0.000 0.0);
--color-text: oklch(0.949 0.000 0.0);
--color-text-muted: oklch(0.802 0.000 0.0);
--color-primary: oklch(0.798 0.195 326.3);
--color-primary-foreground: oklch(0.159 0.000 0.0);
--color-accent: oklch(0.8207 0.1502 90.01);
--color-border: oklch(0.528 0.000 0.0);
--color-focus-ring: oklch(0.798 0.195 326.3);
--color-success: oklch(0.839 0.130 164.9);
--color-success-solid: oklch(0.759 0.143 165.0);
--color-success-solid-foreground: oklch(0.168 0.000 0.0);
--color-warning: oklch(0.839 0.140 75.1);
--color-warning-solid: oklch(0.7605 0.1539 75.30);
--color-warning-solid-foreground: oklch(0.168 0.000 0.0);
--color-error: oklch(0.700 0.171 27.0);
--color-error-solid: oklch(0.732 0.165 27.5);
--color-error-solid-foreground: oklch(0.168 0.000 0.0);
--color-info: oklch(0.780 0.120 245.0);
--color-info-solid: oklch(0.760 0.132 244.8);
--color-info-solid-foreground: oklch(0.168 0.000 0.0);
}
}Tailwind CSS v4 @theme
@theme {
/* light */
--color-background: oklch(0.991 0.000 0.0); /* #fcfcfc */
--color-surface: oklch(0.997 0.000 0.0); /* #fefefe */
--color-text: oklch(0.222 0.000 0.0); /* #1b1b1b */
--color-text-muted: oklch(0.460 0.000 0.0); /* #585858 */
--color-primary: oklch(0.501 0.200 325.1); /* #9827a0 */
--color-primary-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
--color-accent: oklch(0.5242 0.1084 80.64); /* #8a6200 */
--color-border: oklch(0.657 0.000 0.0); /* #919191 */
--color-focus-ring: oklch(0.449 0.200 324.8); /* #871090 */
--color-success: oklch(0.5422 0.1184 162.29); /* #00845a */
--color-success-solid: oklch(0.545 0.122 160.9); /* #008558 */
--color-success-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
--color-warning: oklch(0.5651 0.1234 68.77); /* #a46600 */
--color-warning-solid: oklch(0.8335 0.1508 76.88); /* #ffba44 */
--color-warning-solid-foreground: oklch(0.168 0.000 0.0); /* #0f0f0f */
--color-error: oklch(0.4603 0.1706 26.95); /* #a21a1b */
--color-error-solid: oklch(0.551 0.187 27.1); /* #c8322e */
--color-error-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
--color-info: oklch(0.540 0.120 245.0); /* #2274af */
--color-info-solid: oklch(0.5501 0.1324 245.13); /* #1377b9 */
--color-info-solid-foreground: oklch(0.991 0.000 0.0); /* #fcfcfc */
/* dark: use as dark:bg-background-dark, or remap under a .dark selector */
--color-background-dark: oklch(0.200 0.000 0.0); /* #161616 */
--color-surface-dark: oklch(0.244 0.000 0.0); /* #202020 */
--color-text-dark: oklch(0.949 0.000 0.0); /* #eeeeee */
--color-text-muted-dark: oklch(0.802 0.000 0.0); /* #bebebe */
--color-primary-dark: oklch(0.798 0.195 326.3); /* #fc8bff */
--color-primary-foreground-dark: oklch(0.159 0.000 0.0); /* #0d0d0d */
--color-accent-dark: oklch(0.8207 0.1502 90.01); /* #eabf3a */
--color-border-dark: oklch(0.528 0.000 0.0); /* #6b6b6b */
--color-focus-ring-dark: oklch(0.798 0.195 326.3); /* #fc8bff */
--color-success-dark: oklch(0.839 0.130 164.9); /* #6ce5b5 */
--color-success-solid-dark: oklch(0.759 0.143 165.0); /* #3bcd9a */
--color-success-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
--color-warning-dark: oklch(0.839 0.140 75.1); /* #ffbc56 */
--color-warning-solid-dark: oklch(0.7605 0.1539 75.30); /* #e9a11d */
--color-warning-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
--color-error-dark: oklch(0.700 0.171 27.0); /* #f66d62 */
--color-error-solid-dark: oklch(0.732 0.165 27.5); /* #ff7a6d */
--color-error-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
--color-info-dark: oklch(0.780 0.120 245.0); /* #71bfff */
--color-info-solid-dark: oklch(0.760 0.132 244.8); /* #61b9ff */
--color-info-solid-foreground-dark: oklch(0.168 0.000 0.0); /* #0f0f0f */
}shadcn/ui variables (:root and .dark)
:root {
--background: oklch(0.991 0.000 0.0);
--foreground: oklch(0.222 0.000 0.0);
--card: oklch(0.997 0.000 0.0);
--card-foreground: oklch(0.222 0.000 0.0);
--popover: oklch(0.997 0.000 0.0);
--popover-foreground: oklch(0.222 0.000 0.0);
--primary: oklch(0.501 0.200 325.1);
--primary-foreground: oklch(0.991 0.000 0.0);
--secondary: oklch(0.997 0.000 0.0);
--secondary-foreground: oklch(0.222 0.000 0.0);
--muted: oklch(0.997 0.000 0.0);
--muted-foreground: oklch(0.460 0.000 0.0);
--accent: oklch(0.997 0.000 0.0);
--accent-foreground: oklch(0.222 0.000 0.0);
--destructive: oklch(0.551 0.187 27.1);
--destructive-foreground: oklch(0.991 0.000 0.0);
--border: oklch(0.657 0.000 0.0);
--input: oklch(0.657 0.000 0.0);
--ring: oklch(0.449 0.200 324.8);
--success: oklch(0.545 0.122 160.9);
--success-foreground: oklch(0.991 0.000 0.0);
--warning: oklch(0.8335 0.1508 76.88);
--warning-foreground: oklch(0.168 0.000 0.0);
--info: oklch(0.5501 0.1324 245.13);
--info-foreground: oklch(0.991 0.000 0.0);
--brand-accent: oklch(0.5242 0.1084 80.64);
}
.dark {
--background: oklch(0.200 0.000 0.0);
--foreground: oklch(0.949 0.000 0.0);
--card: oklch(0.244 0.000 0.0);
--card-foreground: oklch(0.949 0.000 0.0);
--popover: oklch(0.244 0.000 0.0);
--popover-foreground: oklch(0.949 0.000 0.0);
--primary: oklch(0.798 0.195 326.3);
--primary-foreground: oklch(0.159 0.000 0.0);
--secondary: oklch(0.244 0.000 0.0);
--secondary-foreground: oklch(0.949 0.000 0.0);
--muted: oklch(0.244 0.000 0.0);
--muted-foreground: oklch(0.802 0.000 0.0);
--accent: oklch(0.244 0.000 0.0);
--accent-foreground: oklch(0.949 0.000 0.0);
--destructive: oklch(0.732 0.165 27.5);
--destructive-foreground: oklch(0.168 0.000 0.0);
--border: oklch(0.528 0.000 0.0);
--input: oklch(0.528 0.000 0.0);
--ring: oklch(0.798 0.195 326.3);
--success: oklch(0.759 0.143 165.0);
--success-foreground: oklch(0.168 0.000 0.0);
--warning: oklch(0.7605 0.1539 75.30);
--warning-foreground: oklch(0.168 0.000 0.0);
--info: oklch(0.760 0.132 244.8);
--info-foreground: oklch(0.168 0.000 0.0);
--brand-accent: oklch(0.8207 0.1502 90.01);
}Design tokens (DTCG-style JSON)
{
"color": {
"light": {
"background": {
"$type": "color",
"$value": "oklch(0.991 0.000 0.0)",
"$description": "sRGB #fcfcfc"
},
"surface": {
"$type": "color",
"$value": "oklch(0.997 0.000 0.0)",
"$description": "sRGB #fefefe"
},
"text": {
"$type": "color",
"$value": "oklch(0.222 0.000 0.0)",
"$description": "sRGB #1b1b1b"
},
"text-muted": {
"$type": "color",
"$value": "oklch(0.460 0.000 0.0)",
"$description": "sRGB #585858"
},
"primary": {
"$type": "color",
"$value": "oklch(0.501 0.200 325.1)",
"$description": "sRGB #9827a0"
},
"primary-foreground": {
"$type": "color",
"$value": "oklch(0.991 0.000 0.0)",
"$description": "sRGB #fcfcfc"
},
"accent": {
"$type": "color",
"$value": "oklch(0.5242 0.1084 80.64)",
"$description": "sRGB #8a6200"
},
"border": {
"$type": "color",
"$value": "oklch(0.657 0.000 0.0)",
"$description": "sRGB #919191"
},
"focus-ring": {
"$type": "color",
"$value": "oklch(0.449 0.200 324.8)",
"$description": "sRGB #871090"
},
"success": {
"$type": "color",
"$value": "oklch(0.5422 0.1184 162.29)",
"$description": "sRGB #00845a"
},
"success-solid": {
"$type": "color",
"$value": "oklch(0.545 0.122 160.9)",
"$description": "sRGB #008558"
},
"success-solid-foreground": {
"$type": "color",
"$value": "oklch(0.991 0.000 0.0)",
"$description": "sRGB #fcfcfc"
},
"warning": {
"$type": "color",
"$value": "oklch(0.5651 0.1234 68.77)",
"$description": "sRGB #a46600"
},
"warning-solid": {
"$type": "color",
"$value": "oklch(0.8335 0.1508 76.88)",
"$description": "sRGB #ffba44"
},
"warning-solid-foreground": {
"$type": "color",
"$value": "oklch(0.168 0.000 0.0)",
"$description": "sRGB #0f0f0f"
},
"error": {
"$type": "color",
"$value": "oklch(0.4603 0.1706 26.95)",
"$description": "sRGB #a21a1b"
},
"error-solid": {
"$type": "color",
"$value": "oklch(0.551 0.187 27.1)",
"$description": "sRGB #c8322e"
},
"error-solid-foreground": {
"$type": "color",
"$value": "oklch(0.991 0.000 0.0)",
"$description": "sRGB #fcfcfc"
},
"info": {
"$type": "color",
"$value": "oklch(0.540 0.120 245.0)",
"$description": "sRGB #2274af"
},
"info-solid": {
"$type": "color",
"$value": "oklch(0.5501 0.1324 245.13)",
"$description": "sRGB #1377b9"
},
"info-solid-foreground": {
"$type": "color",
"$value": "oklch(0.991 0.000 0.0)",
"$description": "sRGB #fcfcfc"
}
},
"dark": {
"background": {
"$type": "color",
"$value": "oklch(0.200 0.000 0.0)",
"$description": "sRGB #161616"
},
"surface": {
"$type": "color",
"$value": "oklch(0.244 0.000 0.0)",
"$description": "sRGB #202020"
},
"text": {
"$type": "color",
"$value": "oklch(0.949 0.000 0.0)",
"$description": "sRGB #eeeeee"
},
"text-muted": {
"$type": "color",
"$value": "oklch(0.802 0.000 0.0)",
"$description": "sRGB #bebebe"
},
"primary": {
"$type": "color",
"$value": "oklch(0.798 0.195 326.3)",
"$description": "sRGB #fc8bff"
},
"primary-foreground": {
"$type": "color",
"$value": "oklch(0.159 0.000 0.0)",
"$description": "sRGB #0d0d0d"
},
"accent": {
"$type": "color",
"$value": "oklch(0.8207 0.1502 90.01)",
"$description": "sRGB #eabf3a"
},
"border": {
"$type": "color",
"$value": "oklch(0.528 0.000 0.0)",
"$description": "sRGB #6b6b6b"
},
"focus-ring": {
"$type": "color",
"$value": "oklch(0.798 0.195 326.3)",
"$description": "sRGB #fc8bff"
},
"success": {
"$type": "color",
"$value": "oklch(0.839 0.130 164.9)",
"$description": "sRGB #6ce5b5"
},
"success-solid": {
"$type": "color",
"$value": "oklch(0.759 0.143 165.0)",
"$description": "sRGB #3bcd9a"
},
"success-solid-foreground": {
"$type": "color",
"$value": "oklch(0.168 0.000 0.0)",
"$description": "sRGB #0f0f0f"
},
"warning": {
"$type": "color",
"$value": "oklch(0.839 0.140 75.1)",
"$description": "sRGB #ffbc56"
},
"warning-solid": {
"$type": "color",
"$value": "oklch(0.7605 0.1539 75.30)",
"$description": "sRGB #e9a11d"
},
"warning-solid-foreground": {
"$type": "color",
"$value": "oklch(0.168 0.000 0.0)",
"$description": "sRGB #0f0f0f"
},
"error": {
"$type": "color",
"$value": "oklch(0.700 0.171 27.0)",
"$description": "sRGB #f66d62"
},
"error-solid": {
"$type": "color",
"$value": "oklch(0.732 0.165 27.5)",
"$description": "sRGB #ff7a6d"
},
"error-solid-foreground": {
"$type": "color",
"$value": "oklch(0.168 0.000 0.0)",
"$description": "sRGB #0f0f0f"
},
"info": {
"$type": "color",
"$value": "oklch(0.780 0.120 245.0)",
"$description": "sRGB #71bfff"
},
"info-solid": {
"$type": "color",
"$value": "oklch(0.760 0.132 244.8)",
"$description": "sRGB #61b9ff"
},
"info-solid-foreground": {
"$type": "color",
"$value": "oklch(0.168 0.000 0.0)",
"$description": "sRGB #0f0f0f"
}
}
}
}Open in the studio
Take the primary colour into the picker, build a tonal scale from it, or check any pair of your own.
Open #9827A0 in the OKLCH picker →Build a tonal scale →Check a pair
FAQ
- Can a bold brand colour pass AA?
- Usually yes. Contrast comes from lightness, so a saturated hue at the right lightness works. The cost is that the shade needed for text on white is deeper than the bright version.
- What about white text over a hero image?
- Put it on a solid or gradient scrim and test the lightest part of the image under the text. This palette's surface and text pairs can serve for the scrim.
- Do headlines need less contrast?
- Large text, at 24 px or 18.66 px bold and up, needs 3:1 for AA and 4.5:1 for AAA under WCAG. The table shows both large-text results.
- How do I test the whole page?
- Sample the key pairs in the contrast checker and consider the browser bookmarklet described on the developers page.