Accessibility (a11y) — design view
Status: 🟩 COMPLETE Last updated: 2026-06-19 Plain-English tagline: Designing so that EVERYONE can use what you build — not just users with perfect vision, hearing, fine motor control, and English as a first language. The design decisions, not the ARIA attributes.
In plain English
Accessibility (often shortened to a11y — “a” + 11 letters + “y”) is the practice of designing software so people with disabilities can use it. About 15% of the world’s population has some form of disability — vision impairments, hearing impairments, motor limitations, cognitive differences, photosensitivity, color blindness. That’s roughly 1 billion people. Designing only for the median user excludes them.
Accessibility splits into two halves:
- Technical a11y — the HTML/ARIA/keyboard mechanics. Covered in accessibility.md under Section 02.
- Design a11y — the decisions that determine whether the product is usable for non-median users. That’s this entry.
The design half matters because a beautifully accessible HTML page (perfect ARIA, perfect labels, perfect focus management) is still inaccessible if:
- The button colors don’t have enough contrast for someone with low vision
- The font is too small for someone with mild vision loss
- The form has a 10-second timeout that someone with motor impairment can’t meet
- The error messages are only conveyed by color
- The animation triggers vestibular symptoms in someone with motion sensitivity
- The video has no captions for someone deaf
The design decisions encode access. The technical decisions enforce the design. Both matter; this entry is about the first.
A surprising truth: accessibility improvements help EVERYONE. Captions help in noisy offices. High contrast helps in bright sun. Larger tap targets help everyone (especially older users, even without diagnosed motor impairment). Keyboard navigation helps power users. Building accessibly produces a better product universally.
Why it matters
Three reasons accessibility isn’t optional:
-
The user base is large. 15% of users. If you exclude them, you’re shipping software for 85% of your potential audience. Especially relevant for products with broad reach (education, government, healthcare, civic).
-
It’s a legal requirement in many jurisdictions. The US ADA, the EU’s EAA (European Accessibility Act, mandatory from June 2025), the UK Equality Act — all require accessible digital products. Non-compliance is increasingly litigated.
-
Accessibility lifts overall UX. Sites that pass WCAG AA are measurably faster, more readable, more reliable, more keyboard-friendly. The “boring” a11y improvements are quality improvements across the board.
The trade-off: doing a11y properly takes thought. Auto-fix tools (axe, Lighthouse) catch some issues but miss the ones design choices create. A meaningful percentage of “accessible-looking” sites still fail real users.
The WCAG framework
The standard for web accessibility is WCAG (Web Content Accessibility Guidelines), published by the W3C. WCAG 2.2 (2023) is the current version; WCAG 3.0 is in draft.
WCAG has three conformance levels:
| Level | What it means |
|---|---|
| A | Bare minimum. Critical barriers removed. |
| AA | The legally-required level in most jurisdictions. Most “we are accessible” products mean this. |
| AAA | Highest level. Some criteria are impractical for general websites; AAA isn’t expected as a global target. |
For Bible Quest-style projects, aim for WCAG 2.2 AA. It’s the consensus floor.
WCAG’s principles (the “POUR” framework):
- Perceivable — users must be able to perceive the content (visually, audibly, or via assistive tech)
- Operable — users must be able to interact with everything (via keyboard, mouse, touch, voice)
- Understandable — content and behavior must be predictable and clear
- Robust — works with assistive technology (screen readers, voice control, switch input)
Each principle has specific success criteria; you check your product against them.
The big design decisions that affect access
1. Color contrast
Text must have sufficient contrast against its background. WCAG AA minimums:
| Text size | Minimum contrast ratio |
|---|---|
| Body text (under 18px) | 4.5:1 |
| Large text (18px+, or 14px+ bold) | 3:1 |
| UI components (button borders, focus rings) | 3:1 |
Use a contrast checker (the WebAIM Contrast Checker is canonical) on every color pairing in your design. A pale gray on white is almost always too low.
This SINGLE rule eliminates more accessibility issues than any other.
2. Don’t rely on color alone
A pattern that uses color as the only signal:
- Red = error, green = success — invisible to red-green colorblind users (~8% of men)
- “The required fields are in red” — invisible to colorblind users
- Charts that distinguish only by hue — invisible
The fix: pair color with another signal. Icons, text labels, patterns, shape, position. “Error” should have an ❌ icon AND red color, not just red.
3. Touch targets — 44×44 px minimum
WCAG 2.5.5 (Level AAA, but widely adopted) and Apple/Material guidelines all recommend 44 px minimum for tap targets. Smaller targets fail users with motor impairments (Parkinson’s, arthritis, tremor).
This rule applies to: buttons, links, icons used as controls, form fields, anything tappable.
4. Focus indicators
Every interactive element needs a visible focus indicator (the ring/outline) when navigated via keyboard. Removing focus indicators (outline: none) WITHOUT replacing them is a critical accessibility failure.
Modern best practice:
- Use the browser’s default focus ring as a fallback
- Customize per design (must remain visible and high-contrast)
- 2px minimum thickness
- Visible against any background the focused element might be on
Tailwind’s focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary is a sane default.
5. Text size and readability
- Base body text 16px minimum. Smaller than that is hard to read for many users, especially on mobile.
- Line height 1.5 (150%) minimum for body text — WCAG 1.4.12.
- Line length 60-80 characters maximum — beyond that, eyes lose track of the line.
- Don’t justify text — uneven word spacing hurts readability, especially for dyslexic readers.
- Sans-serif fonts are generally easier to read on screens; serif works at larger sizes.
6. Motion and animation
- Respect
prefers-reduced-motion— users with vestibular disorders can have nausea, dizziness, or migraines from parallax, large transitions, and spinning content. Disable or reduce motion when set. - No auto-playing video with motion for longer than 5 seconds without a pause control.
- No flashing more than 3 times per second (seizure risk).
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}7. Timeouts and time limits
Avoid hard timeouts on user interactions:
- A form that clears itself after 60 seconds of inactivity is hostile to slow typists
- A login session that expires mid-task and dumps work is hostile
- A captcha with a 10-second solve window is hostile
When timeouts are necessary (security, legal), give a clear warning (“You’ll be logged out in 1 minute — extend?”) and an easy way to extend.
8. Forms — labels, errors, structure
- Every input has a visible label. Placeholder text is NOT a label — it disappears when typing.
- Error messages near the field, not just at the top of the form
- Don’t disable the submit button silently. Show what’s missing or wrong.
- Group related fields with
<fieldset>and<legend>. - Use the right input types (
email,tel,date,number) — they trigger the right keyboards and validators.
9. Images, icons, and media
- Every meaningful image has alt text. Describe the image’s purpose, not its appearance.
- Decorative images get
alt=""so screen readers skip them. - Icons used alone must have an
aria-label(e.g.<button aria-label="Close">✕</button>). - Videos need captions for hearing-impaired users.
- Videos need transcripts for deafblind users and SEO bonus.
10. Language and content
- Set the
<html lang="en">attribute so screen readers use the right pronunciation - Write at a 8th-grade reading level for general audiences (Hemingway Editor / Grammarly help)
- Use clear, plain language — jargon excludes
- Don’t write in ALL CAPS for body content — slower to read and screen readers may spell-out each letter
A concrete example: an accessible Bible Quest question card
Here’s a button-card pattern with a11y considered throughout:
<button
type="button"
onClick={() => onSelect(answer)}
aria-pressed={isSelected}
className="
block w-full text-left
min-h-[44px] p-4
border-2 rounded-lg
text-base leading-relaxed
transition-colors
motion-reduce:transition-none
bg-card hover:bg-accent
border-border
aria-pressed:border-primary aria-pressed:bg-primary/10
focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2
focus-visible:outline-none
disabled:opacity-50 disabled:cursor-not-allowed
"
>
<span className="block font-medium">
{isSelected && (
<span aria-hidden="true" className="mr-2">✓</span>
)}
<span className="sr-only">
{isSelected ? "Selected: " : ""}
</span>
{answer.text}
</span>
{answer.note && (
<span className="block mt-1 text-sm text-muted-foreground">
{answer.note}
</span>
)}
</button>What’s happening:
min-h-[44px]— touch target meets minimumtext-base leading-relaxed— 16px+ text, 1.5+ line heightaria-pressed={isSelected}— screen reader knows the toggle state- Visual signal (border, background, ✓) AND textual signal (
sr-only“Selected: ”) — not relying on color alone focus-visible:ring-2 focus-visible:ring-primary— visible focus indicatormotion-reduce:transition-none— respects user’s motion preferencedisabled:opacity-50 disabled:cursor-not-allowed— clear disabled state with proper cursor- Hover state distinct from selected state — works for keyboard-only users
- No color-only signaling — selected state has visual ✓, text marker, and color
Six small choices that together make this component work for users on screen readers, keyboard, touch, low vision, color blindness, and motion sensitivity.
How to actually verify a11y
Three layers of checks:
1. Automated tools (catches ~30% of issues)
- axe DevTools (browser extension) — runs WCAG checks on any page
- Lighthouse a11y audit — built into Chrome
- ESLint plugin
jsx-a11y— catches common issues at code-write time - WAVE — visual a11y annotations overlay
These catch missing alt text, low contrast, missing labels — the mechanical issues. They CAN’T catch design problems like “this animation triggers migraines.”
2. Manual keyboard testing (catches another ~40%)
Unplug your mouse. Navigate the entire page with Tab, Shift+Tab, Enter, Space, arrow keys.
- Can you reach every interactive element?
- Is the focus indicator visible at every step?
- Is the focus order logical (top to bottom, left to right)?
- Can you escape modals and dropdowns?
- Do you get trapped anywhere (focus that cycles inside one section)?
Most a11y bugs reveal themselves in five minutes of keyboard-only testing.
3. Screen reader testing (catches the rest)
The dominant screen readers:
- VoiceOver (macOS, iOS) — Cmd+F5 to toggle
- NVDA (Windows) — free, the most-used desktop screen reader
- JAWS (Windows) — commercial, used widely in enterprise
- TalkBack (Android)
Try navigating your app with one for 10 minutes. You’ll discover whether labels are clear, headings are structured, and the experience is logical without sight.
For Bible Quest-style projects, the minimum bar: axe DevTools clean + keyboard navigation works + monthly screen reader spot-check.
Common gotchas
-
outline: nonewithout replacing it is the #1 a11y violation. Removes focus indication entirely. Keyboard users can’t tell where they are. Either keep the browser default or replace with a custom visible style. -
Placeholder is not a label. It disappears the moment users type. Use a visible label (or
aria-labelif you must) for every input. -
Click handlers on
<div>are invisible to screen readers and keyboards. Use<button>for actions;<a>for navigation. The browser’s default keyboard + screen-reader support comes free. -
Color contrast is rarely “just enough.” A 4.5:1 button on a 4.5:1 background already fails because the EFFECTIVE ratio (after blending) is lower. Test in context, not in isolation.
-
Touch target spacing matters too. Three 44×44 buttons jammed against each other are still hard to hit. Allow at least 8 px of space between targets.
-
tabindex="0"makes a div focusable;tabindex="-1"removes it from tab order. Don’t settabindex="5"(a positive number) — it overrides the natural document order and creates confusion. -
Skip-to-content links matter. A keyboard user shouldn’t have to Tab through 30 nav items to reach the main content. Add a “Skip to main content” link at the top, visible on focus.
-
Headings have semantic meaning. Use
<h1>once per page (the main heading), then<h2>for major sections,<h3>for subsections. Don’t pick heading levels for visual size — use CSS for that. -
aria-labelon a<button>overrides its visible text. If you set both, screen readers read the aria-label, not the button text. Use either, not both. -
Buttons inside buttons are invalid HTML and confusing for screen readers. Restructure.
-
Animation triggers can cause real harm. Photosensitive epilepsy is rare (1 in 100,000) but vestibular sensitivity (motion sickness, dizziness from parallax) affects ~30% of people. The cost of
prefers-reduced-motionis nothing; the benefit is real. -
Don’t disable zoom.
<meta name="viewport" content="user-scalable=no">is an accessibility violation. Users with low vision must be able to zoom. -
Time-based content excludes some users. Auto-advancing carousels, video-only content, anything that requires fast reaction — all problematic. Provide pause/extend controls.
-
Tooltips on hover are invisible to touch and keyboard. Make tooltip content reachable via long-press, focus, or always-visible.
-
Modal dialogs need focus management. When opening: focus moves into the modal. Tab cycles inside. Escape closes it. Focus returns to the trigger when closed. Frameworks (Radix UI, Headless UI, shadcn) handle this; rolling your own modal is a frequent a11y miss.
-
Don’t auto-focus inputs aggressively. Auto-focus on every page reload disorients screen-reader users who lose their place. Use sparingly.
-
alt=""is for purely decorative images. A photo of a sunset that’s just visual filler. A logo that’s also a link to home?alt="Home"(describe the destination). A chart?alt="Bar chart showing 60% completion"(describe the data). -
PDFs are usually inaccessible. Most PDFs lack proper tags, headings, and reading order. Avoid PDFs for important content; use HTML instead.
-
Forms with errors should announce them. Just showing “Email is invalid” visually doesn’t help a screen-reader user who just submitted. Use
aria-live="polite"regions, or focus the first error. -
Drag-and-drop is a deep a11y problem. Many users can’t drag. Provide a keyboard alternative (e.g. “move up” / “move down” buttons) or radio-based selection.
-
A “dark mode toggle” should respect
prefers-color-scheme. Users with sensitivity to light/dark may have set their OS preference. Default to it; let users override. -
High contrast mode breaks naive styling. Windows users with high-contrast mode see the OS-imposed colors. Test in it (
Settings → Ease of Access → High contrast). -
display: noneremoves content from screen readers. Useful for hidden content; counterproductive for “visually hidden but readable” content. Use the.sr-onlyutility (clip the visible area but keep it in the DOM). -
Decorative animation in icons can be excluded. Loading spinners that just visually rotate should have
aria-hidden="true"and an accompanying live region:<span aria-live="polite" class="sr-only">Loading…</span>. -
Spelling matters for screen readers. A misspelled word can be pronounced unpredictably. Use a spell checker.
-
Live regions can be over-used. Marking everything as
aria-live="assertive"creates a flood of announcements. Usepolitefor non-critical updates; reserveassertivefor true errors. -
Don’t make accessibility someone else’s problem. “We’ll add a11y later” almost always becomes “we never added a11y.” Build it in from day one — it’s much harder to retrofit.
-
Test with REAL users when you can. Automated tools and your own keyboard testing catch a lot. Watching a user who actually uses a screen reader (or has motor impairment, or is colorblind) reveals issues no checklist would find.
-
role="button"on a div is a smell. It tells assistive tech “this is a button” but doesn’t add keyboard handlers or default behavior. Use a real<button>instead. -
AI-generated UI rarely passes a11y on first try. Run axe / Lighthouse on every AI-generated component. Fix the easy things (missing labels, low contrast); the rest needs human review.
A small starter checklist for every page
Before shipping a new page, check:
- Text contrast 4.5:1 minimum (3:1 for large text)
- Visible focus indicators on every interactive element
- Tab order is logical
- All images have alt text (or
alt=""if decorative) - All form inputs have labels
- All icon-only buttons have
aria-label - No information conveyed by color alone
- Page works without a mouse
- Headings are properly nested (h1 → h2 → h3)
-
prefers-reduced-motionis respected - Page passes axe DevTools with no critical issues
Five minutes per page; dramatically more accessible products.
See also
- Accessibility (technical) 🟩 — the HTML/ARIA/keyboard mechanics
- Mobile-first thinking 🟩 — many overlapping concerns
- UX principles 🟩
- Color theory for devs 🟩 — contrast is a color-theory problem
- Typography basics 🟩 — text size + line height are a11y concerns
- Dark mode design 🟥
- Forms and validation 🟩 — forms are where a11y fails most
- HTML 🟩 — semantic HTML is the foundation
- ui 🟩 — built on accessible Radix primitives
- Glossary: a11y, WCAG, ARIA, Screen reader
Sources
- WCAG 2.2 quick reference — the authoritative checklist
- WebAIM Contrast Checker — paste two colors, get the ratio
- axe DevTools — Chrome/Firefox extension; runs WCAG checks on any page
- The A11y Project — community-maintained practical a11y resources
- Inclusive Components (book) — Heydon Pickering’s pattern library for accessible UI
- Accessible to All (Google) — Google’s guide
- GOV.UK Service Manual — Accessibility — practical, government-tested guidance
- European Accessibility Act (EAA) — EU law from June 2025