Interactive accessibility learning for digital teams
Learn Web Accessibility by Seeing It Break
WCAG in Practice is a free way to learn web accessibility and WCAG 2.1 and 2.2. Explore interactive UI patterns and common accessibility mistakes side by side: what breaks, who is affected, and the accessible fix with copy-ready code.
Why accessibility matters
95.9% of the top one million home pages have detectable WCAG failures
27% of Canadian adults aged 15 and over report having at least one disability
Source: Statistics Canada, 89-654-X, 2026 (opens in a new tab)
Wave and Axe find errors. We show you how to fix them.
Source: W3C WAI: automated tools need human review (opens in a new tab)
Dev tools
Use wcag-kit in your AI editor
wcag-kit is a free MCP server that brings wcaginpractice.com patterns into any MCP-compatible AI editor. Ask accessibility questions in plain English and get WCAG references, broken patterns, and accessible fixes without leaving your editor.
“I'm building a notification that pops up after a user saves a form. Any accessibility concerns?”
MCP configuration (JSON)
{
"mcpServers": {
"wcag-kit": {
"command": "npx",
"args": ["wcag-kit"]
}
}
}- Cursor:
~/.cursor/mcp.json - Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.json - Other editors:
Check your editor's MCP documentation
Dev tools
WCAG Lens for VS Code
Real-time accessibility diagnostics as you type. Violations appear as red underlines in the editor. Hover to see the WCAG rule and a fix suggestion - before code ships.
How it helps
- Real-time diagnostics as you type in VS Code
- Violations show as red underlines in the editor
- Hover to see the WCAG rule and a fix suggestion
Works alongside wcag-kit: Lens flags issues in the editor; wcag-kit answers deeper questions in your AI assistant.
Interactive UI patterns
Patterns your team already ships - grouped the same way as the playground. Each demo shows common accessibility mistakes, who is affected, and how to fix them. Copy the code when you build or review UI.
Forms & input
Form Validation
WCAG 1.3.1Error messages must be programmatically associated with the fields they describe.- Common mistake: Red text only, no role="alert": screen readers stay silent and labels are not linked to inputs.
- Accessible pattern: htmlFor, aria-invalid, aria-describedby, and role="alert" so errors are announced immediately.
Combobox (List Autocomplete)
WCAG 2.1.1Autocomplete fields must expose combobox semantics, a listbox, and keyboard navigation for suggestions.- Common mistake: Plain input with a div suggestion list: no roles, no aria-expanded, and Arrow keys cannot reach options.
- Accessible pattern: role="combobox" with aria-expanded, aria-controls, aria-activedescendant, and a listbox of options navigable with arrows and Enter.
Date Picker
WCAG 2.1.1Booking calendars must expose a keyboard-operable grid with labelled days, arrow navigation, and Escape to close.- Common mistake: Calendar built from divs: Tab skips days, arrow keys do nothing, and screen readers get no grid context.
- Accessible pattern: Trigger with aria-expanded; dialog with role="grid", day buttons with full aria-labels, arrow keys, Enter to select, Escape to close.
Radio Group & Checkbox Group
WCAG 1.3.1Option groups need fieldset and legend semantics plus a label on every radio and checkbox.- Common mistake: Styled circles with naked inputs and paragraph headings: no group name and no option labels for screen readers.
- Accessible pattern: fieldset and legend per group, native inputs with htmlFor labels, and clear focus styles.
Search
WCAG 4.1.2Site search must use a search landmark, labelled field, listbox results, and a live region for match counts.- Common mistake: Placeholder-only input, icon button with no name, div results, and no announcement when filters update.
- Accessible pattern: role="search", visible label, aria-controls listbox with options, aria-live status for counts, and keyboard navigation with Enter and Escape.
File Upload
WCAG 4.1.2Upload drop zones need a labelled file input, keyboard access, and live announcements for selection and status.- Common mistake: Drag-only div zones, display:none file inputs without labels, and silent success or error feedback.
- Accessible pattern: Label-wrapped sr-only input, drag-and-drop on the zone, and aria-live status for selection, success, and errors.
Overlays & feedback
Modal / Dialog
WCAG 2.1.2Dialogs must trap focus, return it on close, and be announced to assistive technology.- Common mistake: No focus trap or role="dialog": Tab escapes behind the modal and Escape does nothing.
- Accessible pattern: Radix/Shadcn dialog with aria-modal, focus trap, Escape to close, and focus returned to the trigger.
Alert Dialog
WCAG 2.1.2Destructive confirmations need alertdialog semantics, described warnings, and safe default focus on Cancel.- Common mistake: Generic dialog role, focus on Delete, missing aria-describedby, and Escape that confirms the harm.
- Accessible pattern: role="alertdialog", aria-describedby on the warning, focus trap with Cancel focused first, Escape cancels.
Tooltip
WCAG 1.4.13Supplementary tooltips must work on focus and hover, be dismissible with Escape, and stay readable when the pointer moves over them.- Common mistake: Tooltip on mouseenter only, or on focus with no Escape to dismiss - fails hoverable, dismissible, and persistent requirements.
- Accessible pattern: aria-label on the button, aria-describedby to role="tooltip", show on focus and hover, Escape dismisses without moving focus.
Toast / Alert
WCAG 4.1.3Status messages must be announced to screen readers without stealing focus.- Common mistake: Visual toast only: no live region, so screen readers stay silent when the message appears.
- Accessible pattern: aria-live or role=status (and a dismiss control) so the message is read aloud while focus stays put.
Skeleton / Loading State
WCAG 4.1.3Async content needs aria-busy, hidden skeleton placeholders, and live announcements when loading starts and finishes.- Common mistake: Silent skeleton divs, unlabelled spinners, and no announcement when real content replaces placeholders.
- Accessible pattern: aria-live container with aria-busy, aria-hidden skeletons, sr-only status text, and labelled Reload to replay the sequence.
Navigation & layout
Dropdown Menu
WCAG 2.1.1Menus that open on click must be keyboard-operable and expose the correct ARIA roles.- Common mistake: Div-based trigger with no keyboard support: Tab skips it and screen readers announce only "group."
- Accessible pattern: Button with aria-haspopup, aria-expanded, and listbox options navigable via Enter, arrows, and Escape.
Navigation Menu
WCAG 2.4.1Skip links and landmarks help keyboard users bypass repetitive navigation blocks.- Common mistake: Div-based nav items: not focusable, no landmark, and no skip link past repetitive links.
- Accessible pattern: Semantic nav with real links, aria-current, and a skip link that jumps straight to main content.
Breadcrumb
WCAG 2.4.8Breadcrumb trails need a labelled nav, ordered list markup, hidden separators, and aria-current on the current page.- Common mistake: Div-based trails with inline › characters and no aria-current - separators clutter screen reader output.
- Accessible pattern: nav aria-label="Breadcrumb", ol/li items, aria-hidden separators, and aria-current="page" on the current location.
Tabs
WCAG 2.1.1Tab interfaces must expose tablist semantics and support arrow-key navigation between tabs.- Common mistake: Div tabs with colour-only selection: not focusable and arrow keys do nothing.
- Accessible pattern: tablist, tab, and tabpanel roles with aria-selected and keyboard arrows moving focus between tabs.
Accordion
WCAG 4.1.2Expandable sections need a real button, aria-expanded, and a panel that stays available to assistive tech.- Common mistake: Div trigger with display:none panel: not keyboard focusable and content hidden from screen readers.
- Accessible pattern: Button with aria-expanded, aria-controls, and a region panel toggled without removing it from the accessibility tree.
Pagination
WCAG 2.4.1Paged search results need a labelled nav landmark, keyboard-reachable page buttons, and announced page changes.- Common mistake: Div page numbers with colour-only current page: Tab skips controls and screen readers get no page context.
- Accessible pattern: nav with aria-label, button controls with Page N labels, aria-current="page", and aria-live updates when results change.
Infinite Scroll / Load More
WCAG 4.1.3Feed patterns must announce loading and loaded states and offer a keyboard-operable Load more control instead of scroll-only fetching.- Common mistake: Silent DOM appends on scroll, no loading indicator, and no way for keyboard users to load or find new items.
- Accessible pattern: Load more button with aria-label, aria-busy list, polite live regions for loading/loaded/end states, and focus kept on the control after load.
Focus Management
WCAG 2.4.3Single-page apps must move focus and announce content changes when navigating between views.- Common mistake: Focus stays on the nav link after a route change: screen reader users are left behind with no indication anything changed.
- Accessible pattern: Move focus to the new page heading on route change, and announce the new page title via an aria-live region.
Content & structure
Heading Hierarchy
WCAG 1.3.1Headings must use real h1-h6 elements in order so screen reader users can skim the page.- Common mistake: Bold paragraphs as fake headings, skipped levels (h1 then h4), or multiple h1s on one page.
- Accessible pattern: One h1 per page, then h2 for sections and h3 for subsections. Never skip a level for styling.
Image Alt Text
WCAG 1.1.1Images must have meaningful alternative text, or be marked decorative when appropriate.- Common mistake: Generic alt like "image" or "logo": describes the file, not the meaning or link destination.
- Accessible pattern: Alt conveys purpose (or alt="" for decorative); charts include the data in text too.
Color Contrast
WCAG 1.4.3Text and interactive elements need sufficient contrast against their background (WCAG 1.4.3).- Common mistake: Light gray placeholder text, pastel links, or “soft” success greens that look fine but fail 4.5:1.
- Accessible pattern: Test foreground/background pairs (4.5:1 normal text, 3:1 large text) and verify with a contrast checker.
Data Table
WCAG 1.3.1Tables must use semantic markup and headers so screen readers can identify which column or row each cell belongs to.- Common mistake: Div-based table with no th elements: screen readers read cells as a flat list with no column context.
- Accessible pattern: Semantic table with caption, th elements with scope, and aria-sort on sortable columns.
Controls & interaction
Icon Button
WCAG 4.1.2Icon-only controls need accessible names so screen reader users know their purpose.- Common mistake: Icon-only button with no aria-label: screen readers announce only "button" with zero context.
- Accessible pattern: aria-label or sr-only text plus aria-hidden on the icon so users hear "Delete item, button."
Carousel
WCAG 2.1.1Rotating slides need pausable auto-play, real button controls, and clear slide announcements.- Common mistake: Auto-rotating carousel with div controls: cannot pause, Tab skips controls, and slide changes are silent.
- Accessible pattern: Carousel region with Pause first, button Previous/Next/dots, aria-live off while playing, and labelled slide groups.
Progress Indicator
WCAG 4.1.3Multi-step flows must expose progress with a progressbar and announce step changes to assistive technology.- Common mistake: Styled div progress bar and colour-only current step: no aria-valuenow and no live region when steps advance.
- Accessible pattern: role="progressbar" with valuenow/min/max, aria-live status announcements, and aria-current="step" on the active step.
Drag and Drop
WCAG 2.5.7Sortable boards must keep drag for pointer users and provide a keyboard-equivalent way to move items.- Common mistake: HTML draggable cards with no Move control: keyboard users cannot reorder tasks at all.
- Accessible pattern: Labelled task board, Move button menu to other columns, drag still supported, and announcements on every move.
Next steps
Go deeper when you are ready
New here? Check out the user guide. Then explore Learn for disability context, read what changed in WCAG 2.2, use the playground when you implement UI, prep for CPACC from the study hub, use Dev Tools: wcag-kit in your AI editor or WCAG Lens in VS Code (opens in a new tab) , or read why I built this site on About.