OKLCH Studio · Accessible palettes · Special needs

WCAG compliant colour palette: every pair verified at AA

Updated 2026-10-19

Many teams just want a palette they can adopt and be told it passes. This is that page: a straightforward blue-and-magenta palette in which every text pair meets WCAG AA at 4.5:1, every component boundary and focus ring meets 3:1, and each pair is listed with its measured ratio so that reviewers can check it.

The criteria involved are 1.4.3 Contrast (Minimum) for text, 1.4.11 Non-text Contrast for components and graphics, and 1.4.1 Use of Color for the rule that colour is not the only signal. Contrast is one slice of WCAG 2.2; keyboard access, focus visibility, target size and clear language are tested elsewhere.

Unlike the sector pages, this palette does not chase AAA anywhere. That keeps colours livelier and closer to common brand choices, and it is a good default when you do not know your audience. If you do, one of the more specific pages may serve better.

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

Primary buttonSuccessWarningErrorInfo

Light theme

  • Background

    #F5F7F9

    oklch(0.975 0.003 247.9)

    Sample text

  • Surface

    #FCFEFF

    oklch(0.996 0.003 228.8)

    Sample text

  • Text

    #191B1D

    oklch(0.221 0.005 248.1)

    Sample text

  • Muted text

    #56585B

    oklch(0.460 0.005 258.3)

    Sample text

  • Primary

    #2063B0

    oklch(0.500 0.139 254.8)

    Sample text

  • Primary foreground

    #FBFCFD

    oklch(0.991 0.002 247.8)

    Sample text

  • Accent

    #904895

    oklch(0.521 0.140 324.9)

    Sample text

  • Border

    #8C8E92

    oklch(0.646 0.006 264.5)

    Sample text

  • Focus ring

    #0C54A0

    oklch(0.450 0.140 254.9)

    Sample text

  • Success

    #008158

    oklch(0.5333 0.1163 162.37)

    Sample text

  • Success fill

    #008557

    oklch(0.5443 0.1224 160.36)

    Sample text

  • Success fill label

    #FBFCFD

    oklch(0.991 0.002 247.8)

    Sample text

  • Warning

    #A06300

    oklch(0.5541 0.1212 68.45)

    Sample text

  • Warning fill

    #FFBA44

    oklch(0.8335 0.1508 76.88)

    Sample text

  • Warning fill label

    #0F0F10

    oklch(0.169 0.002 286.2)

    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

    #FBFCFD

    oklch(0.991 0.002 247.8)

    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

    #FBFCFD

    oklch(0.991 0.002 247.8)

    Sample text

Appointment confirmed

Secondary text sits on the surface colour.

Link in primary · Accent text

Primary buttonSuccessWarningErrorInfo

Dark theme

  • Background

    #151618

    oklch(0.200 0.004 264.5)

    Sample text

  • Surface

    #1F2122

    oklch(0.246 0.004 228.9)

    Sample text

  • Text

    #ECEFF2

    oklch(0.951 0.005 247.9)

    Sample text

  • Muted text

    #BBBEC2

    oklch(0.800 0.007 255.5)

    Sample text

  • Primary

    #7DC1FF

    oklch(0.790 0.113 247.2)

    Sample text

  • Primary foreground

    #0D0D0E

    oklch(0.160 0.002 286.2)

    Sample text

  • Accent

    #F2A3F6

    oklch(0.820 0.141 325.1)

    Sample text

  • Border

    #696C6F

    oklch(0.530 0.006 247.9)

    Sample text

  • Focus ring

    #7DC1FF

    oklch(0.790 0.113 247.2)

    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

    #0F0F10

    oklch(0.169 0.002 286.2)

    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

    #0F0F10

    oklch(0.169 0.002 286.2)

    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

    #0F0F10

    oklch(0.169 0.002 286.2)

    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

    #0F0F10

    oklch(0.169 0.002 286.2)

    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.

Light theme: 25 pairs
PairWCAG ratioTargetNormal AA / AAALarge AA / AAAAPCA LcAPCA tierCheck
Text on background#191b1d on #f5f7f916.08:1AA 4.5:1Pass / PassPass / Pass+99.2Lc 75: body textOpen in checker
Text on surface#191b1d on #fcfeff17.07:1AA 4.5:1Pass / PassPass / Pass+103.3Lc 75: body textOpen in checker
Muted text on background#56585b on #f5f7f96.64:1AA 4.5:1Pass / FailPass / Pass+79.8Lc 75: body textOpen in checker
Muted text on surface#56585b on #fcfeff7.05:1AA 4.5:1Pass / PassPass / Pass+84.0Lc 75: body textOpen in checker
Primary as link text on background#2063b0 on #f5f7f95.63:1AA 4.5:1Pass / FailPass / Pass+74.8Lc 60: larger content textOpen in checker
Primary as link text on surface#2063b0 on #fcfeff5.97:1AA 4.5:1Pass / FailPass / Pass+79.0Lc 75: body textOpen in checker
Button label on primary#fbfcfd on #2063b05.88:1AA 4.5:1Pass / FailPass / Pass−82.9Lc 75: body textOpen in checker
Accent text on background#904895 on #f5f7f95.51:1AA 4.5:1Pass / FailPass / Pass+74.3Lc 60: larger content textOpen in checker
Accent text on surface#904895 on #fcfeff5.85:1AA 4.5:1Pass / FailPass / Pass+78.4Lc 75: body textOpen in checker
Border on background#8c8e92 on #f5f7f93.05:13:1 (WCAG 1.4.11)Fail / FailPass / Fail+55.2Lc 45: headlines and large textOpen in checker
Border on surface#8c8e92 on #fcfeff3.24:13:1 (WCAG 1.4.11)Fail / FailPass / Fail+59.4Lc 45: headlines and large textOpen in checker
Focus ring on background#0c54a0 on #f5f7f97.00:13:1 (WCAG 1.4.11)Pass / PassPass / Pass+80.6Lc 75: body textOpen in checker
Focus ring on surface#0c54a0 on #fcfeff7.43:13:1 (WCAG 1.4.11)Pass / PassPass / Pass+84.7Lc 75: body textOpen in checker
Success text on background#008158 on #f5f7f94.56:1AA 4.5:1Pass / FailPass / Pass+68.4Lc 60: larger content textOpen in checker
Success text on surface#008158 on #fcfeff4.84:1AA 4.5:1Pass / FailPass / Pass+72.6Lc 60: larger content textOpen in checker
Success badge label on fill#fbfcfd on #0085574.55:1AA 4.5:1Pass / FailPass / Pass−75.2Lc 75: body textOpen in checker
Warning text on background#a06300 on #f5f7f94.56:1AA 4.5:1Pass / FailPass / Pass+68.7Lc 60: larger content textOpen in checker
Warning text on surface#a06300 on #fcfeff4.85:1AA 4.5:1Pass / FailPass / Pass+72.8Lc 60: larger content textOpen in checker
Warning badge label on fill#0f0f10 on #ffba4411.27:1AA 4.5:1Pass / PassPass / Pass+73.2Lc 60: larger content textOpen in checker
Error text on background#a21a1b on #f5f7f97.24:1AA 4.5:1Pass / PassPass / Pass+80.3Lc 75: body textOpen in checker
Error text on surface#a21a1b on #fcfeff7.68:1AA 4.5:1Pass / PassPass / Pass+84.5Lc 75: body textOpen in checker
Error badge label on fill#fbfcfd on #c8322e5.17:1AA 4.5:1Pass / FailPass / Pass−78.3Lc 75: body textOpen in checker
Info text on background#2274af on #f5f7f94.67:1AA 4.5:1Pass / FailPass / Pass+69.3Lc 60: larger content textOpen in checker
Info text on surface#2274af on #fcfeff4.96:1AA 4.5:1Pass / FailPass / Pass+73.5Lc 60: larger content textOpen in checker
Info badge label on fill#fbfcfd on #1377b94.68:1AA 4.5:1Pass / FailPass / Pass−76.2Lc 75: body textOpen in checker
Dark theme: 25 pairs
PairWCAG ratioTargetNormal AA / AAALarge AA / AAAAPCA LcAPCA tierCheck
Text on background#eceff2 on #15161815.68:1AA 4.5:1Pass / PassPass / Pass−96.2Lc 75: body textOpen in checker
Text on surface#eceff2 on #1f212214.00:1AA 4.5:1Pass / PassPass / Pass−94.9Lc 75: body textOpen in checker
Muted text on background#bbbec2 on #1516189.70:1AA 4.5:1Pass / PassPass / Pass−66.4Lc 60: larger content textOpen in checker
Muted text on surface#bbbec2 on #1f21228.66:1AA 4.5:1Pass / PassPass / Pass−65.0Lc 60: larger content textOpen in checker
Primary as link text on background#7dc1ff on #1516189.43:1AA 4.5:1Pass / PassPass / Pass−65.0Lc 60: larger content textOpen in checker
Primary as link text on surface#7dc1ff on #1f21228.42:1AA 4.5:1Pass / PassPass / Pass−63.7Lc 60: larger content textOpen in checker
Button label on primary#0d0d0e on #7dc1ff10.12:1AA 4.5:1Pass / PassPass / Pass+67.0Lc 60: larger content textOpen in checker
Accent text on background#f2a3f6 on #1516189.78:1AA 4.5:1Pass / PassPass / Pass−67.0Lc 60: larger content textOpen in checker
Accent text on surface#f2a3f6 on #1f21228.73:1AA 4.5:1Pass / PassPass / Pass−65.7Lc 60: larger content textOpen in checker
Border on background#696c6f on #1516183.42:13:1 (WCAG 1.4.11)Fail / FailPass / Fail−24.5Below Lc 30Open in checker
Border on surface#696c6f on #1f21223.06:13:1 (WCAG 1.4.11)Fail / FailPass / Fail−23.2Below Lc 30Open in checker
Focus ring on background#7dc1ff on #1516189.43:13:1 (WCAG 1.4.11)Pass / PassPass / Pass−65.0Lc 60: larger content textOpen in checker
Focus ring on surface#7dc1ff on #1f21228.42:13:1 (WCAG 1.4.11)Pass / PassPass / Pass−63.7Lc 60: larger content textOpen in checker
Success text on background#6ce5b5 on #15161811.65:1AA 4.5:1Pass / PassPass / Pass−77.0Lc 75: body textOpen in checker
Success text on surface#6ce5b5 on #1f212210.40:1AA 4.5:1Pass / PassPass / Pass−75.7Lc 75: body textOpen in checker
Success badge label on fill#0f0f10 on #3bcd9a9.47:1AA 4.5:1Pass / PassPass / Pass+64.6Lc 60: larger content textOpen in checker
Warning text on background#ffbc56 on #15161810.84:1AA 4.5:1Pass / PassPass / Pass−72.7Lc 60: larger content textOpen in checker
Warning text on surface#ffbc56 on #1f21229.68:1AA 4.5:1Pass / PassPass / Pass−71.4Lc 60: larger content textOpen in checker
Warning badge label on fill#0f0f10 on #e9a11d8.74:1AA 4.5:1Pass / PassPass / Pass+60.6Lc 60: larger content textOpen in checker
Error text on background#f66d62 on #1516186.27:1AA 4.5:1Pass / FailPass / Pass−46.5Lc 45: headlines and large textOpen in checker
Error text on surface#f66d62 on #1f21225.60:1AA 4.5:1Pass / FailPass / Pass−45.2Lc 45: headlines and large textOpen in checker
Error badge label on fill#0f0f10 on #ff7a6d7.53:1AA 4.5:1Pass / PassPass / Pass+54.2Lc 45: headlines and large textOpen in checker
Info text on background#71bfff on #1516189.13:1AA 4.5:1Pass / PassPass / Pass−63.4Lc 60: larger content textOpen in checker
Info text on surface#71bfff on #1f21228.15:1AA 4.5:1Pass / PassPass / Pass−62.1Lc 60: larger content textOpen in checker
Info badge label on fill#0f0f10 on #61b9ff9.02:1AA 4.5:1Pass / PassPass / Pass+62.0Lc 60: larger content textOpen 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.

Light theme, status fills
PairNormal visionProtanopiaDeuteranopiaTritanopiaHeld to 6
success / warning34.226.038.931.8Shown only
success / error28.616.66.333.0Yes
success / info17.216.315.43.3Shown only
warning / error31.842.037.422.6Shown only
warning / info40.034.244.531.2Shown only
error / info30.324.121.633.0Shown only

Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia

Dark theme, status fills
PairNormal visionProtanopiaDeuteranopiaTritanopiaHeld to 6
success / warning20.911.815.527.5Shown only
success / error28.815.36.431.3Yes
success / info17.715.214.33.8Shown only
warning / error13.313.210.55.5Shown only
warning / info28.526.028.726.2Shown only
error / info28.321.820.829.7Shown only

Fills as simulated:Normal visionProtanopiaDeuteranopiaTritanopia

Why these colours

The primary is a standard blue at OKLCH hue 255 and chroma 0.14, the accent a magenta at hue 325. These are mainstream choices, and the point is that the lightness values are solved, not guessed. For each role, the generator starts from a typical design lightness and moves only as far as the target requires, so colours stay as close to common design intent as compliance allows.

Text is solved to 4.5:1 against both the page background and the card surface, borders to 3:1 against both, and status colours to 4.5:1 as text and as a badge with a label. Hue and chroma are held, and the gamut mapper reduces chroma only where sRGB cannot provide it. The neutrals carry the faintest blue tint.

If you adopt this palette inside an organisation, treat the contrast table as a living document. Record the date, the tool that computed the ratios and the version of the palette, and update the record when colours change. Auditors and procurement teams generally care less about the exact colours than about evidence that contrast was checked systematically.

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 99% of the requested chroma; hue was held throughout.

How to use it

  • Use the table as your allowed-pairs list; any other combination needs its own check.
  • Large text, 24 px or 18.66 px bold and above, needs only 3:1, but the palette targets 4.5:1 for all text so the choice does not depend on size.
  • Remember that passing contrast does not make a page compliant; run a full audit.
  • Keep disabled controls readable enough to recognise, even though WCAG exempts them.
  • Re-run the checks whenever a colour changes, using the contrast checker.

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: #f5f7f9;
  --color-surface: #fcfeff;
  --color-text: #191b1d;
  --color-text-muted: #56585b;
  --color-primary: #2063b0;
  --color-primary-foreground: #fbfcfd;
  --color-accent: #904895;
  --color-border: #8c8e92;
  --color-focus-ring: #0c54a0;
  --color-success: #008158;
  --color-success-solid: #008557;
  --color-success-solid-foreground: #fbfcfd;
  --color-warning: #a06300;
  --color-warning-solid: #ffba44;
  --color-warning-solid-foreground: #0f0f10;
  --color-error: #a21a1b;
  --color-error-solid: #c8322e;
  --color-error-solid-foreground: #fbfcfd;
  --color-info: #2274af;
  --color-info-solid: #1377b9;
  --color-info-solid-foreground: #fbfcfd;
}
.dark {
  --color-background: #151618;
  --color-surface: #1f2122;
  --color-text: #eceff2;
  --color-text-muted: #bbbec2;
  --color-primary: #7dc1ff;
  --color-primary-foreground: #0d0d0e;
  --color-accent: #f2a3f6;
  --color-border: #696c6f;
  --color-focus-ring: #7dc1ff;
  --color-success: #6ce5b5;
  --color-success-solid: #3bcd9a;
  --color-success-solid-foreground: #0f0f10;
  --color-warning: #ffbc56;
  --color-warning-solid: #e9a11d;
  --color-warning-solid-foreground: #0f0f10;
  --color-error: #f66d62;
  --color-error-solid: #ff7a6d;
  --color-error-solid-foreground: #0f0f10;
  --color-info: #71bfff;
  --color-info-solid: #61b9ff;
  --color-info-solid-foreground: #0f0f10;
}

/* oklch() where supported: the same colours, unclipped values of the hex above. */
@supports (color: oklch(0 0 0)) {
  :root {
    --color-background: oklch(0.975 0.003 247.9);
    --color-surface: oklch(0.996 0.003 228.8);
    --color-text: oklch(0.221 0.005 248.1);
    --color-text-muted: oklch(0.460 0.005 258.3);
    --color-primary: oklch(0.500 0.139 254.8);
    --color-primary-foreground: oklch(0.991 0.002 247.8);
    --color-accent: oklch(0.521 0.140 324.9);
    --color-border: oklch(0.646 0.006 264.5);
    --color-focus-ring: oklch(0.450 0.140 254.9);
    --color-success: oklch(0.5333 0.1163 162.37);
    --color-success-solid: oklch(0.5443 0.1224 160.36);
    --color-success-solid-foreground: oklch(0.991 0.002 247.8);
    --color-warning: oklch(0.5541 0.1212 68.45);
    --color-warning-solid: oklch(0.8335 0.1508 76.88);
    --color-warning-solid-foreground: oklch(0.169 0.002 286.2);
    --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.002 247.8);
    --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.002 247.8);
  }
  .dark {
    --color-background: oklch(0.200 0.004 264.5);
    --color-surface: oklch(0.246 0.004 228.9);
    --color-text: oklch(0.951 0.005 247.9);
    --color-text-muted: oklch(0.800 0.007 255.5);
    --color-primary: oklch(0.790 0.113 247.2);
    --color-primary-foreground: oklch(0.160 0.002 286.2);
    --color-accent: oklch(0.820 0.141 325.1);
    --color-border: oklch(0.530 0.006 247.9);
    --color-focus-ring: oklch(0.790 0.113 247.2);
    --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.169 0.002 286.2);
    --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.169 0.002 286.2);
    --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.169 0.002 286.2);
    --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.169 0.002 286.2);
  }
}

Tailwind CSS v4 @theme

@theme {
  /* light */
  --color-background: oklch(0.975 0.003 247.9); /* #f5f7f9 */
  --color-surface: oklch(0.996 0.003 228.8); /* #fcfeff */
  --color-text: oklch(0.221 0.005 248.1); /* #191b1d */
  --color-text-muted: oklch(0.460 0.005 258.3); /* #56585b */
  --color-primary: oklch(0.500 0.139 254.8); /* #2063b0 */
  --color-primary-foreground: oklch(0.991 0.002 247.8); /* #fbfcfd */
  --color-accent: oklch(0.521 0.140 324.9); /* #904895 */
  --color-border: oklch(0.646 0.006 264.5); /* #8c8e92 */
  --color-focus-ring: oklch(0.450 0.140 254.9); /* #0c54a0 */
  --color-success: oklch(0.5333 0.1163 162.37); /* #008158 */
  --color-success-solid: oklch(0.5443 0.1224 160.36); /* #008557 */
  --color-success-solid-foreground: oklch(0.991 0.002 247.8); /* #fbfcfd */
  --color-warning: oklch(0.5541 0.1212 68.45); /* #a06300 */
  --color-warning-solid: oklch(0.8335 0.1508 76.88); /* #ffba44 */
  --color-warning-solid-foreground: oklch(0.169 0.002 286.2); /* #0f0f10 */
  --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.002 247.8); /* #fbfcfd */
  --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.002 247.8); /* #fbfcfd */
  /* dark: use as dark:bg-background-dark, or remap under a .dark selector */
  --color-background-dark: oklch(0.200 0.004 264.5); /* #151618 */
  --color-surface-dark: oklch(0.246 0.004 228.9); /* #1f2122 */
  --color-text-dark: oklch(0.951 0.005 247.9); /* #eceff2 */
  --color-text-muted-dark: oklch(0.800 0.007 255.5); /* #bbbec2 */
  --color-primary-dark: oklch(0.790 0.113 247.2); /* #7dc1ff */
  --color-primary-foreground-dark: oklch(0.160 0.002 286.2); /* #0d0d0e */
  --color-accent-dark: oklch(0.820 0.141 325.1); /* #f2a3f6 */
  --color-border-dark: oklch(0.530 0.006 247.9); /* #696c6f */
  --color-focus-ring-dark: oklch(0.790 0.113 247.2); /* #7dc1ff */
  --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.169 0.002 286.2); /* #0f0f10 */
  --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.169 0.002 286.2); /* #0f0f10 */
  --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.169 0.002 286.2); /* #0f0f10 */
  --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.169 0.002 286.2); /* #0f0f10 */
}

shadcn/ui variables (:root and .dark)

:root {
  --background: oklch(0.975 0.003 247.9);
  --foreground: oklch(0.221 0.005 248.1);
  --card: oklch(0.996 0.003 228.8);
  --card-foreground: oklch(0.221 0.005 248.1);
  --popover: oklch(0.996 0.003 228.8);
  --popover-foreground: oklch(0.221 0.005 248.1);
  --primary: oklch(0.500 0.139 254.8);
  --primary-foreground: oklch(0.991 0.002 247.8);
  --secondary: oklch(0.996 0.003 228.8);
  --secondary-foreground: oklch(0.221 0.005 248.1);
  --muted: oklch(0.996 0.003 228.8);
  --muted-foreground: oklch(0.460 0.005 258.3);
  --accent: oklch(0.996 0.003 228.8);
  --accent-foreground: oklch(0.221 0.005 248.1);
  --destructive: oklch(0.551 0.187 27.1);
  --destructive-foreground: oklch(0.991 0.002 247.8);
  --border: oklch(0.646 0.006 264.5);
  --input: oklch(0.646 0.006 264.5);
  --ring: oklch(0.450 0.140 254.9);
  --success: oklch(0.5443 0.1224 160.36);
  --success-foreground: oklch(0.991 0.002 247.8);
  --warning: oklch(0.8335 0.1508 76.88);
  --warning-foreground: oklch(0.169 0.002 286.2);
  --info: oklch(0.5501 0.1324 245.13);
  --info-foreground: oklch(0.991 0.002 247.8);
  --brand-accent: oklch(0.521 0.140 324.9);
}

.dark {
  --background: oklch(0.200 0.004 264.5);
  --foreground: oklch(0.951 0.005 247.9);
  --card: oklch(0.246 0.004 228.9);
  --card-foreground: oklch(0.951 0.005 247.9);
  --popover: oklch(0.246 0.004 228.9);
  --popover-foreground: oklch(0.951 0.005 247.9);
  --primary: oklch(0.790 0.113 247.2);
  --primary-foreground: oklch(0.160 0.002 286.2);
  --secondary: oklch(0.246 0.004 228.9);
  --secondary-foreground: oklch(0.951 0.005 247.9);
  --muted: oklch(0.246 0.004 228.9);
  --muted-foreground: oklch(0.800 0.007 255.5);
  --accent: oklch(0.246 0.004 228.9);
  --accent-foreground: oklch(0.951 0.005 247.9);
  --destructive: oklch(0.732 0.165 27.5);
  --destructive-foreground: oklch(0.169 0.002 286.2);
  --border: oklch(0.530 0.006 247.9);
  --input: oklch(0.530 0.006 247.9);
  --ring: oklch(0.790 0.113 247.2);
  --success: oklch(0.759 0.143 165.0);
  --success-foreground: oklch(0.169 0.002 286.2);
  --warning: oklch(0.7605 0.1539 75.30);
  --warning-foreground: oklch(0.169 0.002 286.2);
  --info: oklch(0.760 0.132 244.8);
  --info-foreground: oklch(0.169 0.002 286.2);
  --brand-accent: oklch(0.820 0.141 325.1);
}

Design tokens (DTCG-style JSON)

{
  "color": {
    "light": {
      "background": {
        "$type": "color",
        "$value": "oklch(0.975 0.003 247.9)",
        "$description": "sRGB #f5f7f9"
      },
      "surface": {
        "$type": "color",
        "$value": "oklch(0.996 0.003 228.8)",
        "$description": "sRGB #fcfeff"
      },
      "text": {
        "$type": "color",
        "$value": "oklch(0.221 0.005 248.1)",
        "$description": "sRGB #191b1d"
      },
      "text-muted": {
        "$type": "color",
        "$value": "oklch(0.460 0.005 258.3)",
        "$description": "sRGB #56585b"
      },
      "primary": {
        "$type": "color",
        "$value": "oklch(0.500 0.139 254.8)",
        "$description": "sRGB #2063b0"
      },
      "primary-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.002 247.8)",
        "$description": "sRGB #fbfcfd"
      },
      "accent": {
        "$type": "color",
        "$value": "oklch(0.521 0.140 324.9)",
        "$description": "sRGB #904895"
      },
      "border": {
        "$type": "color",
        "$value": "oklch(0.646 0.006 264.5)",
        "$description": "sRGB #8c8e92"
      },
      "focus-ring": {
        "$type": "color",
        "$value": "oklch(0.450 0.140 254.9)",
        "$description": "sRGB #0c54a0"
      },
      "success": {
        "$type": "color",
        "$value": "oklch(0.5333 0.1163 162.37)",
        "$description": "sRGB #008158"
      },
      "success-solid": {
        "$type": "color",
        "$value": "oklch(0.5443 0.1224 160.36)",
        "$description": "sRGB #008557"
      },
      "success-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.991 0.002 247.8)",
        "$description": "sRGB #fbfcfd"
      },
      "warning": {
        "$type": "color",
        "$value": "oklch(0.5541 0.1212 68.45)",
        "$description": "sRGB #a06300"
      },
      "warning-solid": {
        "$type": "color",
        "$value": "oklch(0.8335 0.1508 76.88)",
        "$description": "sRGB #ffba44"
      },
      "warning-solid-foreground": {
        "$type": "color",
        "$value": "oklch(0.169 0.002 286.2)",
        "$description": "sRGB #0f0f10"
      },
      "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.002 247.8)",
        "$description": "sRGB #fbfcfd"
      },
      "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.002 247.8)",
        "$description": "sRGB #fbfcfd"
      }
    },
    "dark": {
      "background": {
        "$type": "color",
        "$value": "oklch(0.200 0.004 264.5)",
        "$description": "sRGB #151618"
      },
      "surface": {
        "$type": "color",
        "$value": "oklch(0.246 0.004 228.9)",
        "$description": "sRGB #1f2122"
      },
      "text": {
        "$type": "color",
        "$value": "oklch(0.951 0.005 247.9)",
        "$description": "sRGB #eceff2"
      },
      "text-muted": {
        "$type": "color",
        "$value": "oklch(0.800 0.007 255.5)",
        "$description": "sRGB #bbbec2"
      },
      "primary": {
        "$type": "color",
        "$value": "oklch(0.790 0.113 247.2)",
        "$description": "sRGB #7dc1ff"
      },
      "primary-foreground": {
        "$type": "color",
        "$value": "oklch(0.160 0.002 286.2)",
        "$description": "sRGB #0d0d0e"
      },
      "accent": {
        "$type": "color",
        "$value": "oklch(0.820 0.141 325.1)",
        "$description": "sRGB #f2a3f6"
      },
      "border": {
        "$type": "color",
        "$value": "oklch(0.530 0.006 247.9)",
        "$description": "sRGB #696c6f"
      },
      "focus-ring": {
        "$type": "color",
        "$value": "oklch(0.790 0.113 247.2)",
        "$description": "sRGB #7dc1ff"
      },
      "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.169 0.002 286.2)",
        "$description": "sRGB #0f0f10"
      },
      "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.169 0.002 286.2)",
        "$description": "sRGB #0f0f10"
      },
      "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.169 0.002 286.2)",
        "$description": "sRGB #0f0f10"
      },
      "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.169 0.002 286.2)",
        "$description": "sRGB #0f0f10"
      }
    }
  }
}

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 #2063B0 in the OKLCH picker →Build a tonal scale →Check a pair

FAQ

Is a palette itself WCAG compliant?
Compliance applies to pages and processes. A palette can only guarantee that specific pairs meet specific criteria, which is what this page documents.
Which WCAG version applies?
The contrast thresholds for 1.4.3 and 1.4.11 are the same in WCAG 2.0, 2.1 and 2.2. This site's tools use the WCAG 2.x relative luminance formula.
What about APCA?
APCA is a different model proposed for WCAG 3 drafts. It is displayed as extra information but WCAG 2.x ratios decide pass or fail on this page.
Can I use these colours commercially?
The values are generated outputs of a method; use them freely. Check your own brand and trademark requirements separately.

← All accessible palettes