Why Accessibility Matters
Accessibility (a11y) ensures your website works for everyone, including people with disabilities. Over 1 billion people worldwide have some form of disability.
- 15% of world population has some form of disability
- 8% of men have color blindness
- Many users rely on keyboards, screen readers, or other assistive tech
- Accessibility improvements benefit ALL users (better UX, SEO)
Types of Disabilities to Consider
| Type | Examples | Assistive Tech |
|---|---|---|
| Visual | Blindness, low vision, color blindness | Screen readers, magnifiers |
| Motor | Limited hand mobility, tremors | Keyboard, voice control, switches |
| Auditory | Deafness, hard of hearing | Captions, transcripts |
| Cognitive | Dyslexia, ADHD, learning disabilities | Clear layout, simple language |
VoiceOver Quick Reference (Mac)
| Action | Keys |
|---|---|
| Enable/Disable VoiceOver | Cmd + F5 |
| Navigate to next element | Ctrl + Option + โ |
| Navigate to previous element | Ctrl + Option + โ |
| Open Rotor (headings, landmarks) | Ctrl + Option + U |
| Read all from here | Ctrl + Option + A |
| Stop reading | Ctrl |
Tab key only moves between interactive elements (buttons, links, inputs).
VoiceOver arrows (Ctrl + Option + โ) read ALL content including headings and paragraphs.
1. Semantic HTML
Using HTML elements for their intended purpose, not just for styling. Screen readers use semantic elements to understand page structure.
โ Non-Semantic (Bad)
No landmarks or heading levels announced!
โ Semantic (Good)
Landmarks and heading levels announced! โ
Key Semantic Elements
| Element | Purpose | VoiceOver Announces |
|---|---|---|
<header> |
Page or section header | "banner" |
<nav> |
Navigation links | "navigation" |
<main> |
Primary content (one per page) | "main" |
<article> |
Self-contained content | "article" |
<aside> |
Sidebar, related content | "complementary" |
<footer> |
Page or section footer | "content info" |
<h1>-<h6> |
Headings (hierarchy matters!) | "heading level X" |
<button> |
Clickable actions | "button" |
Interactive Demo
โ Div "Button"
- Can't Tab to it
- Enter/Space don't work
- Not announced as button
โ Real Button
- Tab focuses it โ
- Enter/Space work โ
- Announced as "button" โ
2. ARIA Attributes
ARIA (Accessible Rich Internet Applications) provides extra information to assistive technologies when HTML alone isn't enough.
Don't use ARIA if native HTML works! A real <button> is better than <div role="button">.
Common ARIA Attributes
role - What the element IS
aria-label - Accessible name (when text isn't visible)
โ No Label
โ With aria-label
aria-labelledby - Reference another element's ID
aria-describedby - Additional description
aria-hidden - Hide from screen readers
aria-live - Announce dynamic changes
โ Silent Update
Status updates but VoiceOver says nothing!
โ Announced Update
3. Keyboard Navigation
All interactive elements must be usable with keyboard only (no mouse). Many users can't use a mouse.
Essential Keyboard Controls
| Key | Expected Action |
|---|---|
| Tab | Move to next focusable element |
| Shift + Tab | Move to previous element |
| Enter | Activate buttons, follow links |
| Space | Activate buttons, toggle checkboxes |
| Arrow keys | Navigate within components (menus, tabs) |
| Escape | Close modals, dropdowns |
Making Custom Elements Keyboard Accessible
โ Click Only
- Can't Tab to it
- Space doesn't toggle
- Not announced as checkbox
โ Full Keyboard Support
4. Focus Management
Users should always know where they are on the page. Focus should be visible and move logically.
Visible Focus Indicators
โ Focus Removed
Tab to these - can't tell which is focused!
โ Clear Focus Ring
Blue ring shows exactly where you are! โ
Focus Trapping in Modals
When a modal is open, Tab should cycle only within the modal, not escape to the page behind.
5. Skip Links
A hidden link that allows keyboard users to skip repetitive navigation and jump directly to main content.
The Problem
The Solution
Implementation
Press Tab on this page. The first thing that focuses is "Skip to main content" at the top!
6. Understanding tabindex
The tabindex attribute controls whether and when an element can be focused with Tab.
The Three Values
| Value | Tab Key | JS .focus() | Use Case |
|---|---|---|---|
tabindex="0" |
โ Yes | โ Yes | Add non-focusable elements to tab order |
tabindex="-1" |
โ No | โ Yes | Programmatic focus only (modals, errors) |
tabindex="1+" |
โ ๏ธ Avoid | โ Yes | Creates confusing order - DON'T USE |
tabindex="0" - Add to Tab Order
tabindex="-1" - Programmatic Focus Only
Common Use Cases for tabindex="-1"
- Skip link targets (
<main id="content" tabindex="-1">) - Error messages that need announcement
- Modal containers
- Focus return after closing dialogs
7. Form Labels & Errors
Every form input must have an associated label that screen readers can announce.
Label Association Methods
โ No Association
โ Proper Label
Error States
โ Error Not Linked
Error exists but not announced with field!
โ Error Linked
8. Images & Alt Text
Images need descriptive alt text so screen reader users understand the content.
Alt Text Decision Tree
Examples
| Type | Bad | Good |
|---|---|---|
| Informative | alt="image" |
alt="Golden retriever playing in park" |
| Functional | alt="magnifying glass" |
alt="Search" |
| Decorative | alt="decorative swirl" |
alt="" (empty) |
| Chart/Graph | alt="chart" |
alt="Sales increased 50% from Q1 to Q4" |
9. Testing Tools
| Tool | Type | What It Does |
|---|---|---|
| axe DevTools | Browser extension | Automated accessibility testing |
| WAVE | Browser extension | Visual overlay of issues |
| Lighthouse | Chrome DevTools | Accessibility audit score |
| VoiceOver | macOS built-in | Screen reader testing |
| NVDA | Windows (free) | Screen reader testing |
| Keyboard only | Manual | Unplug mouse, use Tab/Enter |
Quick Accessibility Checklist
| Check | How to Test |
|---|---|
| Keyboard navigation | Tab through entire page - can you reach everything? |
| Focus visible | Can you always see where focus is? |
| Headings | Use Rotor - logical h1โh2โh3 order? |
| Landmarks | Use Rotor - nav, main, footer present? |
| Images | Navigate to images - meaningful alt text? |
| Forms | Focus inputs - labels announced? |
| Color contrast | Use axe/Lighthouse - 4.5:1 ratio for text? |
๐ Quick Reference
| Issue | Bad | Good |
|---|---|---|
| Buttons | <div onclick> |
<button> |
| Headings | <div class="title"> |
<h1>, <h2>, <h3> |
| Navigation | <div class="nav"> |
<nav> |
| Images | <img src="..."> |
<img alt="description"> |
| Forms | <span>Email</span><input> |
<label>Email <input></label> |
| Icon buttons | <button>๐</button> |
<button aria-label="Search">๐</button> |
| Focus | outline: none |
outline: 3px solid blue |
| Dynamic updates | <div id="status"> |
<div aria-live="polite"> |