Frontend5 min read

Web Accessibility (a11y)

Build accessible web apps - semantic HTML, ARIA roles, keyboard navigation, focus management, color contrast, and screen reader testing.

AccessibilityARIAWCAGScreen ReaderKeyboard Navigation

skill: Web Accessibility (a11y) category: Frontend tags: [Accessibility, ARIA, WCAG, Screen Reader, Keyboard Navigation] readingTime: 5

Accessibility is not an add-on - it's built into the HTML spec. Semantic HTML gets you 80% there automatically. ARIA is for when semantic HTML can't express the component's behavior (custom dropdowns, tabs, modals). The first rule of ARIA: don't use ARIA if a native HTML element does the job.

Workflow

  1. Use semantic HTML before ARIANative HTML elements have built-in accessibility - implicit ARIA roles, keyboard behavior, and screen reader announcements. Custom elements need all of this added manually.
  2. Add ARIA for custom componentsCustom dropdown menus, tabs, modals, and toggles need ARIA attributes to communicate state and role to assistive technologies.
  3. Manage focus for dynamic contentWhen content changes without a page reload (modal opens, route changes), focus must be moved programmatically - otherwise keyboard users are left behind.
  4. Ensure color contrast and visible focusWCAG 2.2 requires 4.5:1 contrast ratio for text. Low contrast is the most common accessibility failure. Focus indicators must be clearly visible for keyboard navigation.
  5. Test with automated tools and real screen readersAutomated tools catch 30-40% of accessibility issues. The rest requires real screen reader testing. Both are necessary.

Output Format

Accessibility: semantic landmarks, ARIA roles/states/properties, focus management with focus-visible, WCAG contrast ratios, and axe automated + screen reader testing.

HTML: header, nav, main, footer landmarks
ARIA: role + aria-label/labelledby + aria-expanded/selected
Focus: useEffect(() => ref.current.focus(), [isOpen])
CSS: :focus-visible outline, never outline:none
Test: jest-axe + VoiceOver/NVDA manual testing

Examples

Input

Output

Edge Cases & Gotchas

  • ARIA live region timing - Content must be injected into an existing aria-live element - inserting the element with content already inside doesn't trigger announcements in most screen readers.
  • Images in links - A link containing only an image needs accessible text: <a href="/"><img alt="Home" src="logo.png"></a>. The img alt becomes the link's accessible name.
  • Form error association - Error messages must be programmatically associated with their input via aria-describedby. Visual proximity is not enough for screen readers.
  • Dynamic route changes - SPA route changes don't trigger screen reader page announcements like HTML page loads. Implement a "skip to main content" link and move focus to main heading on route change.

When to Break These Rules

  • Never skip accessibility - it's a legal requirement in many jurisdictions (ADA, EN 301 549) and serves all users (captions help in noisy environments, keyboard nav helps power users).
  • Don't add ARIA roles to HTML elements that already have the correct semantics - <button role="button"> is redundant and can cause screen reader confusion.

Reference Files

  • https://www.w3.org/WAI/ARIA/apg/
  • https://webaim.org/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.