Phil Wagner

Staff Learning Designer and Technical Writer
Technical Lead of AI Enablement Education

Rubric: control state contrast

Written by a person. Last read by a person on 2026-09-08, 20 days ago. Its facts were checked by the eval suite on 2026-09-28.

Enforced by check_control_contrast.

The claim

Every state a control can be in is legible, in both themes and in every stylesheet.

Observable evidence

The pass bar

The chip's label and its fill are at least 4.5:1 apart in each of four states: pressed, pressed and hovered, pressed and focused, pressed and keyboard-focused. Both themes. Every stylesheet the contract lists, not only the one the site ships.

Why this rubric exists

A control has more colors than the one it rests in, and the rest of them are seen only by somebody who is using it. Nobody photographs a button mid-press, so those colors get no review at all.

This site shipped one. .js .level:focus painted the label in the accent color, and .level[aria-pressed="true"] filled the chip with the same color. The first selector is more specific, so it won. Clicking a chip focuses it. The label and the fill were then the same color, a contrast ratio of 1.00, and the chip read as blank.

Three reviews looked at that page and passed it. Each one looked at a chip nobody had pressed.

Ambiguous cases

Reading the declarations, not the render. The check parses CSS instead of measuring a browser. That keeps it in the eval suite and lets it cover the three design directions as well as the shipped stylesheet, which is where a fix applied to one leaves the other three. It cannot see a color that arrives from an image, a gradient or a filter.

A selector the check cannot parse is a finding. It understands the shapes the chip rules use and refuses the rest of them. Skipping what it cannot read is how the faulty rule got past the three reviews that did look at the file.

4.5:1, not 3:1. The chip label is .78rem, which does not count as large text under the guideline, so it takes the higher of the two bars. Raising the label's size would lower the bar and would have to change this rubric with it.