Short answer
Derive them from the rest colour by small, consistent lightness steps — typically darker on hover and darker again when pressed on light themes — so the label keeps its contrast in every state. Selected states need more than a colour shift, because they persist and carry meaning. Disabled states are exempt from WCAG contrast, but a faded control should still be legible enough for people to see what is unavailable.
Hover and pressed colours confirm that the pointer is over a control and that a click registered. They are transient, and the W3C's guidance on non-text contrast treats hover as supplementary: it does not need to meet a contrast requirement unless it is the only way to identify the control. That gives designers latitude, but the label on the control still has to stay legible in every state. The table builds a primary button in OKLCH and derives hover and pressed by lowering lightness by 0.05 and 0.10. The white label's contrast rises in each state, because the fill is getting darker; had the states lightened the fill instead, the label could have dropped below 4.5:1 while the pointer was over it.
Hover colours are often generated by mixing the base with black or white in sRGB, or by adding a translucent overlay. Both work, but their visual effect varies by hue: a 10% black overlay darkens a yellow button far more noticeably than a navy one. Stepping lightness in OKLCH, or by fixed CIELAB L* amounts, gives a similar perceived change for every colour in the system, so hover feels the same on primary, secondary and danger buttons. The table's last column shows that each step changes the fill's own contrast with the rest colour only slightly — about 1.2 to 1.5:1 — which is enough to notice as feedback but not to act as the only indication of a meaningful state.
Selected tabs, checked checkboxes, toggled switches and chosen options differ from hover: they persist and they tell users about the state of the system. WCAG 1.4.11 applies to the visual information needed to identify such states, so a checked checkbox's tick, or the indicator that shows which tab is selected, needs 3:1 against its adjacent colours. And because 1.4.1 prohibits colour as the only means of conveying information, a selected state should change more than colour — a tick, an underline, a bolder label, a filled rather than outlined shape. A selected tab shown only by a slightly darker background fails both tests for many users.
WCAG exempts inactive components from both text and non-text contrast, recognising that disabled controls are not operable. The common implementation — rendering the control at reduced opacity — can take this too far: at 40% opacity on white, the table's blue button and its label drop to contrasts that make the label hard to read at all. Users still need to know what the disabled control is, so they can find out how to enable it. Good practice is a dedicated disabled token (a neutral grey fill with mid-grey text) rather than opacity, a legible label, and a nearby explanation of why the action is unavailable. Some teams avoid disabled buttons entirely and validate on submit instead, which sidesteps the problem.
| State | Fill | White label vs fill | Fill vs rest colour |
|---|---|---|---|
| Rest | #3A6CCE | 4.98:1 | — |
| Hover (OKLCH L −0.05) | #2C5DBD | 6.16:1 | 1.23:1 |
| Pressed (OKLCH L −0.10) | #1E4EAC | 7.66:1 | 1.53:1 |
| Disabled (40% opacity on white) | #B0C4EB | 1.75:1 (label at 40%) | 2.83:1 |
Why: Hover lightens a fill that carries white text.
Fix: Darken on hover for light themes, or check label contrast in every state.
Why: Selection is a small background-colour change only.
Fix: Add an underline or indicator bar at 3:1 and a bolder label.
Why: Disabled is implemented as low opacity on the whole control.
Fix: Use a dedicated disabled token with a legible label, and explain why it is disabled.
Each statement is labelled by kind — established fact, a standard’s requirement, observed market data, a convention, or Colourwise’s own interpretation or analysis — with the strength of the evidence behind it.
StandardStrong evidence
The W3C's Understanding document for 1.4.11 treats hover styling as supplementary, not requiring contrast unless it is the only means of identifying the control, and states that 1.4.11 does not define a required contrast between focused and unfocused states that differ only by colour.
Source: Understanding Success Criterion 1.4.11: Non-text Contrast (WCAG 2.2)
StandardStrong evidence
WCAG 2.2 exempts inactive (disabled) user-interface components from the text-contrast and non-text-contrast requirements.
Source: Web Content Accessibility Guidelines (WCAG) 2.2; Understanding Success Criterion 1.4.3: Contrast (Minimum) (WCAG 2.2)
Colourwise analysisStrong evidence
Lowering a blue button's OKLCH lightness by 0.05 for hover and 0.10 for pressed raises its white label's contrast in each state, while rendering it at 40% opacity on white drops the label's contrast far below 3:1.
Based on: Computed by Colourwise with OKLCH conversion, sRGB alpha compositing and the WCAG formula; see the table.
Source: Web Content Accessibility Guidelines (WCAG) 2.2; A perceptual color space for image processing (Oklab)
Reviewed 29 September 2026. Colourwise summarises its sources in its own words and does not reproduce standards text or proprietary colour data. Spotted an error? Tell us.