Button Contrast: Text, Borders and Focus

A button has several color relationships. Measure its label, any boundary needed to identify the control, and its focus indicator against the appropriate adjacent colors.

Separate the three tests

A single ratio cannot describe a whole button. A label sits on a fill; the fill or border sits on a page; a focus indicator may sit inside or outside the button. Write down those relationships before entering colors. Otherwise a strong fill-to-page result can hide a weak text-to-fill result.

PartCompare withRelevant check
Button labelThe button fill directly behind the textText contrast: normally 4.5:1 at AA
Necessary boundary or iconIts adjacent color or colorsNon-text contrast: 3:1 when applicable
Custom focus indicatorThe surface adjacent to the visible indicatorNon-text contrast plus separate focus requirements

WCAG does not require every button to have a visible bounding rectangle. If its text or icon already identifies the control, an additional decorative border does not automatically need 3:1. If a boundary is the only way to identify an input or control, that necessary visual cue must have sufficient contrast. Determine the role before treating every decorative edge as a failure.

Work through a button on paper

Consider an opaque white label #FFFFFF on a cobalt fill #4265D6, placed on a warm paper surface #F7F3E8. First check white against cobalt for the label. Then check cobalt against paper if the fill is the cue that identifies the button boundary. These are different pairs even though they belong to one component.

.action {
  color: #FFFFFF;
  background: #4265D6;
}
.action:focus-visible {
  outline: 3px solid #10182B;
  outline-offset: 3px;
}

The sample outline is outside the button, separated by an offset. Its relevant neighbor is the paper surface. Test #10182B against #F7F3E8. If the same button moves onto a dark panel, measure the outline against that panel too. Do not assume that a focus color works on every page merely because it works here.

Pair in this exampleDisplayed ratioInterpretation
White label / cobalt fill5.17:1Passes the 4.5:1 normal-text ratio
Cobalt fill / paper surface4.66:1Above 3:1 if this boundary is required
Ink outline / paper surface15.95:1Strong adjacent-color contrast; inspect focus behavior separately

Check states and small labels

Small labels remain normal text even inside a tall, padded button. A 16 px bold label still needs the normal-text threshold. Hover and pressed states can change the fill, so recalculate text-to-fill contrast for each state. Selected states may introduce a checkmark or another visual cue whose contrast needs its own adjacent-color check.

  1. Record label color, fill, page surface, border and focus colors for the default state.
  2. Repeat the relevant pairs for hover, focus, active, selected and error states that exist in your component.
  3. Check narrow layouts where text size or the surface behind the button changes.
  4. Keep a visible focus indicator and verify actual keyboard use; a color calculation cannot test focus order or activation.

Know what the numeric result leaves open

Inactive controls have contrast exceptions in the cited criteria, but low-contrast styling alone does not establish that a control is inactive. Check its real behavior and semantics. Error, success and selected states should also have visible text or shape cues so people do not need to recognize a hue to understand the state.

The 3:1 target in the checker is a measurement aid for an identified pair. It does not inspect the component to decide whether a boundary is necessary, whether the focus indicator has enough area, whether it is obscured, or whether the button has an accessible name. Review those requirements in the actual interface.

Sources and further reading

Content reviewed: October 26, 2026