Accessibility Library User Guide
Use the contrast map to answer one question — what may I write on this background? — then take a ready set of passing colors, check your own palette and cite pairs from the five-million-pair corpus.
Overview
The Accessibility Library page is a contrast map. Choose a background, which the page calls the ground, and a WCAG 2.x contrast target, and it draws every text color that clears the target on that ground, with the boundary as a line. This guide explains each control and readout, what the numbers mean and where the map's answer stops.
1. What the page answers
+Open the Accessibility Library. The page is headed "What may I write on this?" and answers that for one background at a time. Contrast is a function of two colors, so once the background is fixed, the text colors that pass form a region with an edge. The map draws that region instead of listing pairs one by one.
From top to bottom, the page has five parts:
- The map: the ground and target controls, the color field with its contour lines, and the reading panel beside it.
- "12 that work on this ground": up to twelve text colors that clear the target, with a Copy as CSS button.
- "Or bring your own": paste hex colors to see where they land and what each failure needs.
- "All of this from your own code": a pointer to the REST API that runs the same engine.
- "The index": look up one record of the five-million-pair corpus by id, or scroll through the pairs that pass.
Every figure is computed in your browser. The page fetches one small manifest file and makes no other requests for its data. The corpus size and seed shown under the heading (5,000,000 and 9001) come from that manifest.
2. Choose a ground and a target
+The bar above the map holds both inputs.
| Control | What it does |
|---|---|
| Ground presets | Four buttons: #0D0D0D (near-black), #1D2A3E (navy, the default), #FFFCF7 (cream) and #1B4D3E (deep green). The pressed button is the current ground. On a phone-width screen only the swatches show. |
| Color picker | Sits after the presets. The color you choose in it becomes the ground as you move it. It always shows the current ground, whichever way it was set. |
| Swap | Puts the color under the caret on the ground, and moves the caret to the old ground's lightness and hue — the same two colors, asked the other way round. |
| Target: 3:1, 4.5:1, 7:1 | Chooses the threshold that decides pass and fail everywhere on the page: the grey area, the color of the ratio, the picks, the palette check and the browse filter. 4.5:1 is the default. |
| Territory | The share of the map that clears the current target on this ground, as a percentage. |
Choose the ground first, because it decides how much room you have. At 4.5:1 about 34% of the map passes on the default navy, about 24% on the deep green and about 57% on the cream. A stricter target always leaves less; on the navy, 7:1 leaves about 23%.
3. Read the map
+The map is a slice of OKLCH color space. Hue runs left to right from 0° to 360°, and lightness runs from 1.0 at the top to 0 at the bottom. Each point shows the most saturated color that hue and lightness can hold in sRGB, so the slice has no gaps. It is drawn as 72 columns, one every 5° of hue.
- The lines: one contour per threshold — dashed amber for 3:1, solid green for 4.5:1 body text and dashed light blue for 7:1 AAA. For every hue, each line marks the lightness where contrast with the ground crosses that ratio. All three are always drawn.
- The passing side: on a dark ground the colors that pass lie above the line; on a light ground they lie below it. The failing side of the current target is drained to grey, so what keeps its color is what you may use.
- Why the line is not flat: at the same OKLCH lightness, yellow carries far more luminance than blue, so the boundary rises and falls across the hues. "Make it darker" is advice that depends on the hue.
- Hues that never pass: if no lightness at a hue reaches the target, that column is grey from top to bottom and the line has no point there.
The hue labels under the map (0° red, 60° yellow, 120° green and so on) are rough guides only. The axis is OKLCH hue, where pure sRGB yellow sits near 110° and pure blue near 264°. Read the Hue row in the panel for the exact angle.
4. Move the caret and read the panel
+The ring on the map is the caret: the text color being tested. Click or drag anywhere on the map to move it. The sample paragraph in the panel is set in that color on the ground, and every row updates while you drag.
| Readout | Meaning |
|---|---|
| Large ratio | The WCAG 2.x contrast ratio of the caret color against the ground, to two decimals. It turns to the failing color when it is below the current target. |
| Verdict | Independent of the target: "clears AAA for body text" at 7:1 or more, "clears AA for body text" at 4.5:1 or more, "large text and UI only" at 3:1 or more, otherwise "fails every text threshold". |
| Foreground | The caret color as a hex value. |
| Ground | The current ground. |
| Lightness | The caret's OKLCH lightness, from 0 to 1. |
| Hue | The caret's OKLCH hue in degrees. |
| APCA | The APCA Lc value of the pair, rounded. It is signed: positive for dark text on a lighter ground, negative for light text on a darker ground. |
| Vision margin | The smallest color difference left between the two colors across ten simulated vision conditions, from 0 (the same color under at least one) to 1 (as far apart as black and white). |
| To the line | How far the caret is from the current target's line at this hue, in OKLCH lightness points. Positive means inside the passing region with that much to spare; negative means outside by that much. "unreachable at this hue" means no lightness at this hue can pass. |
Under the rows, one sentence reports how much lightness you have to spare, or how far outside you are and whether the line sits above or below you at this hue. To get in, change the lightness at the same hue toward the line: lighter on a dark ground, darker on a light one.
5. What the thresholds mean
+The three targets are the WCAG 2.x contrast thresholds. The page measures contrast only; whether your text counts as large, or whether a color marks a control, is for you to judge.
| Target | WCAG 2.x use | Success criterion |
|---|---|---|
3:1 |
Large text at level AA (at least 18 point, or 14 point bold — about 24 and 18.66 CSS pixels). Also the visual boundaries and states of user-interface components, and graphics needed to understand content. | 1.4.3 Contrast (Minimum); 1.4.11 Non-text Contrast |
4.5:1 |
Normal text at level AA. Also large text at level AAA. | 1.4.3 Contrast (Minimum); 1.4.6 Contrast (Enhanced) |
7:1 |
Normal text at level AAA. | 1.4.6 Contrast (Enhanced) |
The contrast ratio is (L1 + 0.05) / (L2 + 0.05), where L1 and L2 are the WCAG relative luminances of the lighter and the darker color. It runs from 1:1 to 21:1 and does not depend on which color is the text.
APCA is shown for reference only. It is the perceptual contrast method in the WCAG 3 drafts, which are not a standard yet, and no target on this page is based on it. Read its size; the sign only gives the polarity.
The vision margin simulates protanopia, protanomaly, deuteranopia, deuteranomaly, tritanopia, tritanomaly, achromatopsia and achromatomaly with color matrices, plus a yellowing cataract filter and a low-vision loss of contrast. It measures how far apart the two colors stay in each and shows the worst of the ten. Use it to spot pairs that rely on hue alone. It is not a clinical measure, and the page sets no pass mark for it.
6. Use the picks and copy them as CSS
+Under the map, the band headed "12 that work on this ground" gives ready answers. The page tries twelve hues, one every 30° starting at 15°, and sets each 0.10 of OKLCH lightness inside its hue's line so a later tweak has room. Any that still miss the target are dropped, and the number in the heading shows how many remain. On all four preset grounds all twelve survive at every target.
Each pick shows sample text in that color on the ground, with its ratio and hex value. The picks change with the ground and the target. Click a pick to move the caret onto it, so the panel reads it out.
Copy as CSS puts the set on your clipboard as CSS custom properties inside a
:root block: --ground, then --fg-01, --fg-02
and onward, each followed by a comment with its ratio and hue. The button briefly reads
Copied, or Copy failed if the browser refused clipboard access.
This is the page's only export. For the same answers as JSON, use the API (section 12).
7. Check your own palette
+
In "Or bring your own", paste hex colors into the box. Anything written as #RGB or
#RRGGBB is picked up, whatever separates the values; everything else is ignored.
Duplicates are merged and the first 24 are used. The map and the table update a moment after you
stop typing.
Each color is pinned on the map at its own OKLCH lightness and hue. A pin with a red ring fails the current target, and a dashed line runs from it to the line: the move it needs.
| Column | Meaning |
|---|---|
| Colour | The hex value. |
| Here | Its contrast ratio against the current ground, marked as passing or failing the current target. |
| Lightness | Its OKLCH lightness as a percentage. |
| Needs | "nothing" if it passes; otherwise the OKLCH lightness points it has to move to reach the line at its hue, or "unreachable" when that hue cannot pass on this ground. |
The Needs figure is a distance, printed with a plus sign in every case: the move is toward lighter on a dark ground and toward darker on a light ground. It is measured to the line, which is drawn for the most saturated color at each hue, so for a muted color treat it as a starting point and check the ratio again after the change.
8. Look up and cite a record
+"The index" at the bottom of the page is a corpus of five million foreground/background pairs. They are defined by a seed rather than stored, so anyone who reads a citation can recompute the same pair.
Type a record id such as acc_91, or a plain index such as 325, and press
Look up or Enter. A record id is acc_ followed by the index
in base 36, so those two examples are the same record. The result shows:
- Pair: the foreground on the background, as hex values, with a sample.
- Contrast: the WCAG 2.x ratio.
- APCA: the signed Lc value, rounded.
- Auric SD: the site's composite score out of 100 and its grade — S, A, B, C, D or F.
- Recommended for: the strongest use the pair qualifies for.
- A note giving the seed, the index and its batch: the numbers that reproduce the pair.
The Auric SD score weights WCAG contrast and APCA at 30% each, the average vision-simulation
distance at 20%, and the OKLCH lightness gap and hue separation at 10% each. Recommended for takes
the first rule the pair meets: body-text-strict (score 85, 7:1, APCA Lc 75 and a vision
margin of 0.30), body-text-WCAG3 (Lc 75), body-text-AA (4.5:1),
large-text (3:1), ui-only (Lc 45), spot-text (Lc 30),
non-text (Lc 15), otherwise decorative. The Lc rules follow the WCAG 3
drafts and are not a conformance claim.
Something that is not an id or a number gets "Not a record id". An index past the end gets "Out of range"; indices run from 0 to 4,999,999.
9. Browse the corpus
+Below the lookup, the index scrolls. Two buttons choose what it lists: Pairs that pass, the default, keeps only pairs that clear the current target, and Everything shows the corpus as it is. About 88% of the corpus fails 4.5:1, so Everything is mostly color you may not use for text.
The counter reads "N shown · scanned M of 5,000,000": how many pairs are listed and how far into the corpus the page has looked. With Pairs that pass on, the note under the list gives the pass rate so far. Keep scrolling and more are found. Nothing is downloaded, because each record is computed from the seed, and only the cards near the screen exist, so the list does not slow down however far you go.
Each card shows sample text, the ratio, the two hex values and the record id. Click a card to load it into the map: its background becomes the ground and the caret moves to its foreground's lightness and hue. Changing the target restarts the list while Pairs that pass is on.
10. Keyboard and screen readers
+The map is a single control in the tab order. Focus it, then use:
| Key | Effect |
|---|---|
| Left / Right arrow | Hue down or up by 5°, wrapping round at 360°. |
| Up / Down arrow | Lightness up or down by 0.02. |
| Shift with an arrow | Five times the step: 25° of hue or 0.10 of lightness. |
| Home | Lightness 1, the top of the map. |
| End | Lightness 0, the bottom of the map. |
Screen readers treat the map as a slider. Its value is the hue, and its spoken text is the whole reading, for example "#00d2ca on #1D2A3E, 7.64 to 1, passes 4.5:1 for body text" at the defaults. The reading panel is a live region, and everything the map shows is also written there as text. The ground, target and browse buttons report whether they are pressed. In the lookup box, Enter runs the lookup.
11. Where the numbers come from
+
The map, the picks and the palette check are calculated by the page's own color engine as you work
and need no data at all. The index uses
/data/accessibility-db/accessibility.json, a manifest of under 3 KB, for four numbers
that define the corpus:
| Field | Value |
|---|---|
count | 5000000 |
seed | 9001 |
batch_size | 50000 |
batch_seed_stride | 2654435761 |
Each record is six bytes from an xorshift32 random stream: foreground red, green and blue, then background red, green and blue. The stream restarts for every batch of 50,000 records from the seed plus the batch number times the stride, so reaching a record means stepping through its own batch only, not the whole corpus. If the manifest cannot be loaded, the page uses these same values.
12. Use it from your own code
+The band "All of this from your own code" points to six REST endpoints that run the same engine as the page, so the page and the API give the same answer:
POST /v1/accessibility/map— the lines and territory for a ground.POST /v1/accessibility/picks— a passing set, like the picks band.POST /v1/accessibility/audit— a palette checked against a ground, with a fix for each failure.GET /v1/accessibility/corpus,/corpus/statsand/corpus/{record_id}— browse, measure and cite the corpus.
A line under the heading, which you can dismiss, also names POST /v1/accessibility/map
and what one call costs in API credits. The page itself computes everything locally and does not
call these endpoints. Keys, parameters, responses and costs are covered in
The Accessibility Corpus API
and the API endpoint reference.
13. Tips and limits
+- Choose the background before the text color, and compare backgrounds by their Territory.
- Contrast is not the whole of legibility. Check text size and weight (the large-text allowance), every state of a control, and the real rendering in your interface.
- The ratio is calculated from the exact color, and the hex value is rounded to whole RGB steps, so checking the hex elsewhere can differ in the second decimal place. Leave a margin near a threshold; the picks already sit 0.10 of lightness inside the line.
- The map looks on one side only. A ground with a relative luminance under 0.18 is treated as dark, and the map looks for lighter text; any other ground is treated as light, and it looks for darker text. On a mid-tone ground, colors on the other side can pass too, especially at 3:1, but the map does not draw them.
- The map shows the most saturated color at each point. After Swap or after opening a corpus card, the caret sits at the right lightness and hue, but the panel reads the map's color there, which can be more saturated than the color you started from.
- On browse cards, a ratio under 4.5:1 is shown in the failing color even when the target is 3:1.
- The page has no URL parameters of its own. The site-wide page state saved in the address (
#p=) keeps the scroll position, the ground (through the color picker) and a pasted palette, but not the target or the caret, so a copied address does not reproduce a reading. Copy the CSS, or note the hex values or the record id. - The APCA value and the vision margin are guidance; neither is a WCAG 2.x conformance test.
To check one pair in detail, use the Color Contrast Checker. For how the page is built, see the Accessibility Library Developer Reference; for the generator package behind the corpus, see the Accessibility Gen Developer Reference.
14. Troubleshooting
+| What you see | What to do |
|---|---|
| The map is empty and the panel shows dashes | The page needs JavaScript. Reload it. The map does not depend on the network, so a slow or failed manifest download does not stop it. |
| A pasted color does not appear | It must start with # and have 3 or 6 hex digits. Eight-digit hex with alpha, rgb() and color names are ignored, and only the first 24 different colors are used. |
| Fewer than 12 picks | Some hues cannot reach the target on this ground even 0.10 inside the line. Lower the target, or choose a ground further from a mid-tone. |
| "unreachable at this hue" | No lightness at that hue reaches the target on this ground. Change the hue, the target or the ground. |
| Copy as CSS says Copy failed, or nothing happens | The browser blocked clipboard access, or offers none on this connection. Allow clipboard access for the site and use the https address. |
| "Not a record id" | Use acc_ followed by letters and digits, such as acc_91, or digits only. |
| "Out of range" | The index is past the end of the corpus. Indices run from 0 to 4,999,999. |
| The browse list grows slowly at 7:1 | Only about 3.6% of pairs clear 7:1, so the page looks through more records for each card. Keep scrolling, or lower the target. |