Color and UI

Ensure Readable UI Text Contrast

Use this page to run a context-first contrast workflow, validate normal and state-specific text pairings, and finalize a clear handoff only after replacements are documented.

Answer First

If the text color cannot be read against its final background in real UI conditions, this workflow says do not publish the component. You must test exact foreground and background combinations in place, record why each pair passes or fails, then only hand over approved replacements tied to a state plan.

Core Workflow

This page is a production handoff guide, not a lab note sheet. The goal is one consistent decision record per screen area, with no ambiguity around which color roles were tested, how they failed, and what to replace. Use it for dark mode, light mode, focused states, active states, hover states, and disabled states whenever user comprehension depends on text legibility.

The workflow is designed to be deterministic. Start from the source of truth, test the exact rendering context, and only move forward when every required state is either passing or has an approved fallback color plan.

Before You Measure

Preparation controls correctness. If setup is weak, contrast checks will look right in screenshots and fail in production.

  • Confirm the component context: modal, card, button, input, table cell, tooltip, and toast each count as distinct surfaces.
  • Collect role-based color names from the design system, such as primary-text, secondary-text, surface, surface-muted, border, and error background. Never test unnamed ad hoc values as if they were reusable tokens.
  • List the required text sizes with their role and weight, for example body 14 px normal, label 12 px medium, title 18 px bold.
  • Note if any state uses transparency, blur, or gradient overlays. Those are separate test cases and need separate entries.
  • Make sure the component is loaded at its final width and zoom level, because scaling can change anti-aliasing and apparent edge clarity.

Practical Six-Step Procedure

  1. Define a check target by pairing one text role with one background role and one state label, for example primary button text vs primary button background in disabled state.
  2. Capture the exact rendered values from the implementation, not only design files. If a token resolves to a different CSS variable in theme mode, test that resolved value.
  3. Run a first pass on default state text at normal size, then rerun for large size where available. Record both outcomes separately.
  4. Run state passes for hover, focus, active, selected, disabled, error, warning, and success if they appear in production. Never treat one passing state as proof of all states.
  5. For overlays and translucent layers, test the blend outcome against the real underlying surface. For gradients, test multiple sample points along the gradient where text may appear.
  6. Write a short decision note for each pair: pass, fail, or reroute through another token. For fail entries, assign a replacement candidate before moving to the next pair.

Decision Rules

Use strict rules to reduce false confidence and speed handoff conversations.

  • Rule 1. Test against final painted background, not isolated swatches.
  • Rule 2. Evaluate normal and large text paths separately.
  • Rule 3. Validate all interactive states. A pass in default state does not guarantee a pass in hover or disabled.
  • Rule 4. Treat semi-transparent text colors as their composited value over each possible surface.
  • Rule 5. For gradient surfaces, test at the lowest contrast point along the gradient path, not only the center.
  • Rule 6. Do not approve a pair with visual legibility comments but no numeric evidence, and do not reject solely on ratio without usability context.
  • Rule 7. Never replace a color only after one pass. Always rerun the dependent pair set so changes are coherent across related components.

Decision Matrix Template

Keep entries small and repeatable.

  • Item ID: component and variant, for example nav-chip-secondary.
  • Foreground: token or hex.
  • Background: token or hex.
  • State: default, hover, focused, pressed, selected, disabled.
  • Text size class: normal, medium, large.
  • Result: pass, pass with caution, fail.
  • Action: keep, tighten, replace pair, or defer.
  • Owner and timestamp: who checked, when.
  • Handoff notes: what to change before release.

Limits and Boundaries

Contrast checks are a strong signal, not the only usability condition. This process does not replace semantic headings, typography clarity, content length control, line spacing, focus visibility, icon affordance, or cognitive load checks.

Use this workflow only for text readability decisions. If a pair is visually readable but still fails strict thresholds because of very large fonts or visual style, decide based on the component goal and document the exception only after design review. If text is interactive, include keyboard focus and pointer feedback in a separate accessibility review.

Common Mistakes to Avoid

  • Using brand guide colors alone without validating against actual rendered surfaces.
  • Skipping disabled or error states because they are less visible in mockups.
  • Reusing a single color decision for every theme and component size.
  • Accepting a passing ratio while readable distance fails at small sizes due to cramped spacing.
  • Recording only raw colors and missing role names, which creates ambiguity in implementation.
  • Stopping after one run and shipping without a recheck after edits.

Stop Condition

Stop this workflow when all high-impact text pairs have role-level outcomes and an explicit replacement path for each failing pair, and no additional states are left untested. If a new surface, theme, or component variant appears, do not continue with assumptions. Return to the checklist for the new case, because assumptions are the most common source of late regressions.

Handoff and Related Tool

Once checks complete, create a handoff package with three files or notes: 1) the check table, 2) the approved replacement list, and 3) notes for unresolved exceptions. Include links to the related source components so implementation changes remain traceable.

Contrast Checker is the next step for mechanical reruns after this review. Run the tool only after decisions are set, then compare output against this guide before updating shared files.

Hand off with these acceptance lines: all tested pairs documented, all failing pairs assigned to either replace or defer with reason, and no pending state without owner or due date.

Quick Daily Workflow

For ongoing work, use this 10 minute rhythm. First 2 minutes: confirm changed components and states. Next 4 minutes: validate high priority text-background pairs in default and hover state. Next 3 minutes: validate disabled and focused states for input-like components. Final minute: log fail list and route decisions. If anything is blocked, mark stop condition and defer until the next design or engineering checkpoint.