Catch real-world failures early
Goal: Screen readers and keyboards must understand the page without CSS.
-
☐ No interactive behavior on
div/span -
☐ Every interactive element has:
- a native role
- an accessible name
-
☐ Landmarks exist and are unique where required (
main) -
☐ Headings reflect document structure, not visual size
-
☐ Visual reordering (Flex/Grid) does not change reading order
-
☐ Tables are not used for layout (ever)
Quick test: Disable CSS → page still reads logically.
Goal: Information is perceivable under poor vision or harsh conditions.
-
☐ Text contrast ≥ 4.5:1
-
☐ Large text ≥ 3:1
-
☐ Focus rings, borders, icons ≥ 3:1
-
☐ Disabled states are not color-only
-
☐ Error/success states include text or icons
-
☐ System preferences respected:
prefers-reduced-motionprefers-contrast(when used)
Quick test: Grayscale mode → meaning remains intact.
Goal: Users always know where they are.
-
☐ Every tabbable element has a visible focus state
-
☐ Focus styles are:
- not clipped
- not subtle
- not animated
-
☐
:focus-visibleused (keyboard ≠ mouse) -
☐ Focus order follows DOM order
-
☐ Opening UI (menus/dialogs) moves focus in
-
☐ Closing UI restores focus
Quick test: Tab continuously → never lose focus.
Goal: No mouse required, ever.
-
☐ All functionality reachable via keyboard
-
☐ No keyboard traps (except intentional modals)
-
☐ Custom controls support:
Enter→ activateSpace→ toggle
-
☐ Hover-triggered UI has keyboard equivalent
-
☐ Skip link exists and is focus-visible
Quick test: Mouse unplugged → task completion still possible.
Goal: ARIA never lies or duplicates HTML.
- ☐ ARIA used only when native HTML cannot express intent
- ☐ No redundant roles on native elements
- ☐ No ARIA without keyboard support
- ☐ State attributes (
aria-expanded, etc.) are always accurate - ☐ Live regions used sparingly and intentionally
Rule: Bad ARIA is worse than no ARIA.
Goal: Content survives user overrides.
- ☐ Usable at 400% zoom
- ☐ No fixed heights on text containers
- ☐ Text spacing overrides don’t break layout
- ☐ Horizontal scrolling avoided (except data tables)
- ☐ Logical properties preferred (
inline/block)
Quick test: Browser zoom + large text → no clipping.
Goal: Errors are discoverable and fixable.
-
☐ Labels are visible and persistent
-
☐ Required fields indicated in text
-
☐ Errors:
- appear near the field
- are described in text
- are announced when updated
-
☐ Placeholder text is never instructional
A page fails if any of these fail:
- ☐ Keyboard-only walkthrough
- ☐ Screen reader smoke test
- ☐ CSS-disabled read-through
- ☐ Focus visibility check
If the page:
- works without CSS,
- works without JS,
- and reads sensibly when linearized,
then it is likely accessible in practice—not just compliant.
Recommended next step: apply this checklist per component (button, menu, dialog, form) rather than per page to prevent regressions.