Reusable code
Accessibility Snippets
Copy reusable HTML, React, and Tailwind snippets for accessible UI patterns.
Foundation Snippets
Start with native HTML and add ARIA only when the component needs extra relationships or state.
Skip link
Place this as the first focusable item in the page.
<a href="#main-content" class="sr-only focus:not-sr-only">
Skip to main content
</a>
<main id="main-content">
Page content
</main>Accessible icon button
Use visible text when possible. For icon-only controls, provide a clear aria-label.
<button type="button" aria-label="Delete report" className="focus-ring rounded p-2">
<TrashIcon aria-hidden="true" />
</button>Current page nav link
Use aria-current for the active page in a navigation set.
<nav aria-label="Primary navigation">
<a href="/">Home</a>
<a href="/dashboard" aria-current="page">Dashboard</a>
</nav>Forms and Errors
Accessible forms need visible labels, helpful instructions, specific errors, and predictable focus behavior.
Accessible form field with error
Connect labels, help text, and errors with id/htmlFor/aria-describedby.
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-invalid={hasError}
aria-describedby={hasError ? "email-error" : "email-help"}
/>
<p id="email-help">Use your work email address.</p>
{hasError ? <p id="email-error">Enter a valid email address.</p> : null}Error summary
Move focus to the summary after submit only when validation fails.
<div role="alert" tabindex="-1" aria-labelledby="form-errors-title">
<h2 id="form-errors-title">Fix these errors</h2>
<ul>
<li><a href="#email">Enter a valid email address.</a></li>
<li><a href="#password">Password must be at least 8 characters.</a></li>
</ul>
</div>Required field
Use visible text and native required when the field is truly required.
<label for="name">Name <span aria-hidden="true">*</span></label>
<input id="name" name="name" required aria-describedby="name-required">
<p id="name-required">Required field.</p>Interactive Components
These snippets show structure. Production components still need focus management and keyboard tests.
Accessible modal structure
Add focus trap, Escape close, background inert behavior, and focus return in the component.
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Export report</h2>
<p>Choose a format for your accessibility report.</p>
<button type="button">Export PDF</button>
<button type="button" aria-label="Close export dialog">Close</button>
</div>Accordion section
A real button controls one panel and exposes expanded state.
<h3>
<button type="button" aria-expanded={open} aria-controls="panel-keyboard">
Keyboard testing
</button>
</h3>
<div id="panel-keyboard" hidden={!open}>
Keyboard testing content.
</div>Toast alert
Use status for non-urgent updates and alert for urgent errors.
<div role="status" aria-live="polite" className="rounded border p-4">
Report copied to clipboard.
</div>Tabs shell
Add arrow-key handling and keep aria-selected synchronized with the active panel.
<div role="tablist" aria-label="Accessibility topics">
<button role="tab" aria-selected="true" aria-controls="panel-wcag" id="tab-wcag">
WCAG
</button>
<button role="tab" aria-selected="false" aria-controls="panel-aria" id="tab-aria">
ARIA
</button>
</div>
<section id="panel-wcag" role="tabpanel" aria-labelledby="tab-wcag">WCAG content</section>
<section id="panel-aria" role="tabpanel" aria-labelledby="tab-aria" hidden>ARIA content</section>Tables and Responsive Content
Tables and scrollable regions need semantics, labels, and keyboard access.
Accessible table
Use captions and header cells so data relationships are clear.
<table>
<caption>Monthly scan usage</caption>
<thead>
<tr>
<th scope="col">Month</th>
<th scope="col">Scans</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">June</th>
<td>42</td>
</tr>
</tbody>
</table>Keyboard reachable scroll region
Use tabindex only when the region itself needs keyboard scrolling.
<div tabindex="0" role="region" aria-label="Transaction history" class="max-h-80 overflow-y-auto">
Long scrollable content
</div>Responsive code block
Make long code keyboard-scrollable and give it context.
<pre tabindex="0" aria-label="HTML example" class="overflow-x-auto">
<code><button type="button">Save</button></code>
</pre>