--- category: principles topic: accessibility-floor content_type: synthesis status: latest retrieved: 2026-05-13 tags: [accessibility, wcag, contrast, keyboard, focus, aria, touch-targets, motion, synthesis] sources: - kb/reference/standards/wcag/color-contrast - kb/reference/standards/wcag/keyboard-and-focus - kb/reference/standards/wcag/components - kb/reference/foundations/color/contrast-and-accessibility --- # Accessibility Floor — Synthesis ## How to use this document This document states requirements as constraints. Every "must" is either a WCAG 2.2 AA requirement (the current legal standard for most regulated products) or a well-established practical minimum that any professional design system must satisfy. Each requirement includes a verification method. Reference this document at the end of every campaign step that produces CSS, components, or interaction patterns. It is a checklist, not a guide. --- ## 1 — Color contrast ### 1.1 Text contrast (WCAG 1.4.3 — AA) **Normal text (< 18pt / < 14pt bold) must have ≥ 4.5:1 contrast** against its background. Normal text in web contexts means: body text, labels, captions, placeholder text, button labels, link text — any text under 24px regular weight or under ~18.67px bold weight. **Large text (≥ 18pt / ≥ 14pt bold) must have ≥ 3:1 contrast** against its background. Large text in web contexts: headings at 24px+ (regular), or ~19px+ (bold). **Verify:** WebAIM Contrast Checker (webaim.org/resources/contrastchecker), browser DevTools color picker, or the Colour Contrast Analyser desktop app. Enter foreground hex + background hex; confirm the ratio meets the threshold for the text size. **Exemptions:** Disabled (inactive) text, decorative text that conveys no information, logotypes. Placeholder text is not exempt — it is text. --- ### 1.2 UI component contrast (WCAG 1.4.11 — AA) **Visual boundaries that identify interactive components must have ≥ 3:1 contrast** against adjacent colors. This applies to: input field borders, checkbox and radio outlines, toggle switch tracks, button outlines (on outlined/ghost variants), focus ring outlines when author-provided, chart lines and data markers when required for comprehension. **Verify:** Measure the border or boundary element against the surface it sits on (not the element's content). A `#cccccc` border on white background = 1.6:1 — fails. A `#767676` border on white = 4.54:1 — passes. **Exemptions:** Filled buttons where the background color itself identifies the button (the background must still meet 3:1 against the page background). Disabled components. --- ### 1.3 Dark mode contrast is a separate verification **Contrast must be verified independently in dark mode.** WCAG 2.x contrast ratios do not automatically transfer between modes. The WCAG formula overstates perceived contrast for near-dark color pairs. A token pair that passes 4.5:1 in light mode may pass the formula in dark mode while being functionally harder to read, because the formula is not perceptually uniform at the low-luminance end. **Verify:** Run contrast checks against your dark mode token values explicitly. If your design system uses tonal palettes (HCT/OKLab), verify tone differences are ≥ 50 for normal text, ≥ 40 for large text and UI, in addition to running the WCAG formula. **APCA as a supplemental check:** APCA (Lc values) is perceptually uniform and more reliable for dark mode. Target Lc ≥ 75 for body text, Lc ≥ 60 for informational text, Lc ≥ 45 for headings. APCA is not yet normative (WCAG 2.x remains the legal standard), but use it to catch dark-mode false positives — pairs that pass WCAG 2.x but are visually unreadable. --- ### 1.4 No raw color values in components **Components must consume color tokens.** No hardcoded hex values, HSL declarations, or inline `rgba()` in component styles. **Verify:** Search the component codebase for `#`, `rgb(`, `hsl(`, and `rgba(` in style rules. Each match is a violation unless it is in the token definition itself. --- ## 2 — Keyboard navigation ### 2.1 All interactive elements must be keyboard-reachable (WCAG 2.1.1 — A) **Every interactive element must be reachable and operable by keyboard alone.** No functionality may be available only via mouse, touch, or pointer. Required keyboard behaviors: - Button: `Enter` or `Space` to activate - Link: `Enter` to activate - Checkbox: `Space` to toggle; arrow keys to move between grouped options - Radio group: arrow keys to navigate between options - Modal: `Tab`/`Shift+Tab` within modal; `Escape` to close - Dropdown menu: arrow keys to navigate; `Enter` or `Space` to select; `Escape` to close - Tab panel: arrow keys between tabs; `Tab` moves into panel content **Verify:** Unplug the mouse. Tab through every interactive element in the component. Confirm every element is reachable and can be activated. Any element that cannot be reached or operated is a violation. Custom components built on non-semantic elements (`div`, `span`) must add `tabindex="0"` and keyboard event handlers. Any drag-and-drop pattern must have a keyboard alternative. --- ### 2.2 No keyboard traps (WCAG 2.1.2 — A) **Focus must never become permanently stuck in a component.** If keyboard focus can enter a component, it must be able to exit. Note: trapping focus *within* a modal dialog is correct and required behavior. What is forbidden is making it impossible to dismiss the modal and release focus. **Verify:** Tab into every interactive component. Confirm you can always tab out, close, or otherwise move focus away using only the keyboard. --- ### 2.3 Tab order must follow visual order **The tab order must match the visual reading order.** Users should not find focus jumping unexpectedly across the layout. **Verify:** Tab through a page from top to bottom. Confirm focus moves in the same order a sighted user would visually scan the content. If focus jumps, check for positive `tabindex` values (tabindex > 0) — these override natural DOM order and are almost always incorrect. Remove them. --- ## 3 — Focus visibility ### 3.1 Focus indicator must be visible (WCAG 2.4.7 — AA) **Keyboard focus must always be visible.** The focused element must be distinguishable from its unfocused state. `outline: none` or `outline: 0` without a replacement focus style is a WCAG violation. **Minimum focus style:** ```css :focus-visible { outline: 2px solid; outline-offset: 2px; } ``` The `:focus-visible` pseudo-class is correct for implementations that show focus only during keyboard navigation. `:focus` alone shows the ring on mouse-click as well — both approaches are compliant; `:focus-visible` is the modern preference. **Verify:** Tab through the page. Confirm every focused element has a visible, distinguishable indicator. If you can't immediately see which element has focus, the indicator is insufficient. --- ### 3.2 Focus indicator contrast (WCAG 1.4.11 applied to focus rings) **The focus ring must have ≥ 3:1 contrast** against the adjacent background color. A 2px solid `#005fcc` ring on white background = ~5.9:1 — passes. A light gray ring on a white background will fail. **Verify:** Measure the focus ring color against the surface it appears on using the contrast checker. Meet 3:1 minimum; target higher. --- ### 3.3 Focused element must not be entirely hidden (WCAG 2.4.11 — AA) **When an element receives focus, it must not be completely covered** by sticky headers, cookie banners, fixed navigation, or other author-created overlays. Partial obscuration is permitted at AA. Complete concealment is not. **Fix pattern:** ```css html { scroll-padding-top: [sticky-header-height + 8px]; } ``` **Verify:** Tab through a page with a sticky header. Confirm no focused element is fully hidden behind the header when scrolled into view. --- ## 4 — Touch and pointer targets ### 4.1 Interactive targets must be at minimum 24×24 CSS px (WCAG 2.5.8 — AA) **Every pointer/touch target must be at least 24×24 CSS pixels** in its interactive area, or positioned so that no other target falls within a 24px-diameter circle centered on its bounding box. **Verify:** Inspect the interactive area (not the visual icon) of every small control — icon buttons, close buttons, checkbox hit areas, inline links. Measure in DevTools. Any target below 24×24px that isn't spaced away from other targets is a violation. --- ### 4.2 Target size best practice is 44×44 CSS px (WCAG 2.5.5 — AAA, industry standard) **Target 44×44 CSS px for all primary interactive controls.** This is the AAA threshold, but it is the industry standard for usability (Apple HIG, Material Design, and Carbon all specify 44px minimum). The 24px requirement is the legal minimum. The 44px target is what makes the interface comfortable for users with motor impairments and on small touchscreens. **Implementation:** ```css button, [role="button"], a { min-height: 44px; min-width: 44px; } ``` Use padding to expand the interactive area without changing visual size. An icon button with a 20px icon needs 12px of padding on each side to meet 44px. **Verify:** Inspect the `height` and `width` of every button, link, and interactive control in DevTools. Confirm the interactive area (including padding) meets the target. --- ## 5 — Semantic structure and ARIA ### 5.1 Semantic HTML first (WCAG 4.1.2 — A) **Use semantic HTML elements for all interactive components before reaching for ARIA.** Native elements carry implicit roles, keyboard behavior, and accessibility semantics that custom elements must re-implement manually. | Use this | Not this | |---|---| | `