• CTA
  • Color Contrast
  • UI Design
  • Buttons

CTA Button Colors: Contrast, States, and “Is It Loud Enough?”

Design primary CTA colors that pass WCAG, stay on brand, and remain clear in resting, hover, disabled, and focus states—with invented before/after hex examples.

Sherotree

·6 min read

A call-to-action can fail in two opposite ways: it is so soft it disappears into the page, or so loud that the label becomes unreadable. Designers usually notice the first problem in critique. Users notice the second when they cannot parse “Start free trial” on a neon fill.

This article focuses on button label contrast, state styling, and the tension between brand saturation and WCAG thresholds. All checks can be done with free tools on Uwarp—start with the Colour Contrast Checker.

What “loud enough” should mean

Loud enough means:

  1. The control is easy to find among secondary actions (hierarchy).
  2. The label meets contrast requirements on the fill (legibility).
  3. States still communicate without relying on color alone.

It does not mean maximum saturation. A slightly deeper brand fill with crisp white type often outperforms a brighter fill with grayish white overlays or thin letter-spacing tricks.

Targets for CTA labels

Button labels are usually normal text for WCAG purposes unless the type is truly large/bold by the WCAG definition (~18pt+ or 14pt+ bold). Most product CTAs at 14–16px regular should aim for:

  • AA: ≥ 4.5:1 label vs fill
  • AAA (optional): ≥ 7:1 for high-stakes or long-session products

Large display CTAs on marketing heroes may qualify for the large-text threshold (≥3:1 at AA), but many teams still keep 4.5:1 so the same component token works in denser UI.

Resting, hover, disabled, focus

Design four states as separate contrast pairs—not as opacity afterthoughts.

StateColor jobContrast note
RestingPrimary fill + labelLabel ≥4.5:1 on fill
Hover / pressedDarken or lighten fill; keep labelRe-check label on the new fill; do not assume resting pass carries over
FocusVisible focus ring vs surrounding pageRing should be visible against both the button and the background behind it (non-text contrast thinking: aim for a clear 3:1-style separation)
DisabledMuted fill + muted label or clearer “unavailable” patternAvoid 2:1 gray-on-gray that looks broken; explain why nearby if the action matters

Focus rings that survive brand colors

A white button on a white page needs a dark ring (or a dual ring). A purple button on a purple wash needs a ring that is not also purple. Test focus on the real section background, including hero images—pair decorative backdrops with the habits from SVG/background work and still verify text/button contrast with the contrast checker.

Brand constraints: keep the hue, move the role

Marketing wants the logo color on the CTA. Engineering wants one token. Accessibility wants a readable label. Resolve this with roles:

  • cta-fill — brand-forward, may be the seed
  • cta-label — white or near-white or a near-black if the fill is pastel
  • cta-fill-hover — systematically darker (light theme) or lighter (dark theme)
  • cta-fill-disabled — neutral, not “seed at 30% opacity” by default

If white-on-seed fails 4.5:1, you have three honest fixes:

  1. Darken the fill until white passes.
  2. Switch the label to near-black if the fill is intentionally light (common for secondary “soft” CTAs).
  3. Split tokens: keep the bright seed for large icons/illustrations; use a darker sibling for button fills.

Generate darker/lighter siblings from the seed with Accessible Brand Colors, then confirm the button pair in the contrast checker.

Before / after hex examples (invented)

These pairs are teaching examples—not a brand kit. Always re-check in the tool; do not ship from memory.

Example A — Vivid coral that fights white labels

Before

  • Fill: #FF6B4A
  • Label: #FFFFFF
  • Risk: vivid warm fills often sit near the AA edge for small type; hover at #FF8166 can make it worse.

After

  • Fill resting: #E2573A
  • Fill hover: #C9472F
  • Label: #FFFFFF
  • Soft marketing accent (non-text): keep #FF6B4A for illustrations only

Result: same hue family, safer label pair, hover still darker for affordance.

Example B — Pastel “friendly” CTA that disappears

Before

  • Fill: #DBEafe
  • Label: #60A5FA
  • Hierarchy fails and contrast fails: light blue on lighter blue.

After

  • Fill: #2563EB
  • Label: #FFFFFF
  • Optional secondary soft button: fill #EFF6FF, label #1D4ED8 (check ≥4.5:1)

Result: primary CTA is findable; soft variant remains for low-emphasis actions.

Example C — Dark theme primary

Before

  • Fill: #818CF8
  • Label: #0F172A — may pass, but hover to #A5B4FC can drop label contrast.

After

  • Fill resting: #6366F1
  • Fill hover: #818CF8 with label #0F172A only if that pair still passes; otherwise keep label #FFFFFF on a darker fill #4F46E5
  • Focus ring: #F8FAFC outer + #0F172A gap, or a light ring tested on the dark page background

Lock whichever pair you choose by measuring both resting and hover in the colour contrast checker.

Outline and ghost CTAs

Ghost buttons (transparent fill + border + colored label) create three relationships: label vs page, border vs page, and hover fill vs label. Check the label against the page (resting) and against the hover fill (hover). Many ghost CTAs pass at rest and fail on hover when a soft tint appears behind a mid-tone label.

Secondary vs primary hierarchy without contrast debt

  • One solid primary per view for the forward path.
  • Secondary as outline or neutral solid with its own passing label pair.
  • Tertiary as text button using primary-text-on-surface, not a third neon fill.

If everything is saturated, nothing is a CTA—and contrast bugs multiply.

CTA contrast checklist

  • Resting label vs fill ≥ 4.5:1 (or documented large-text exception).
  • Hover/pressed label vs fill re-checked.
  • Focus ring visible on the real section background.
  • Disabled state is unmistakable without relying on ~2:1 text.
  • Ghost/outline hover state checked as its own pair.
  • Soft brand tints are not used as primary fills unless labels are dark and passing.
  • Dark theme CTAs validated separately.
  • Hex pairs recorded next to tokens; verified in Colour Contrast Checker.
  • If the seed cannot work as a fill, a darker sibling exists via Accessible Brand Colors.

Quick build recipe

  1. Drop the brand seed into Accessible Brand Colors.
  2. Candidate a fill that supports white (or near-black) labels.
  3. Confirm resting + hover in the contrast checker.
  4. Add focus and disabled as explicit styles.
  5. Browse related utilities under color tools if you need supporting scales.

Suggested next article

Return to the WCAG Color Contrast Guide for body text, UI chrome, and the failure cases that show up outside buttons—then keep CTAs as the strictest pair in your file.