π Accessibility training
Learn accessibility by example
Each lesson below shows the same component built two ways: an inaccessible version and an accessible one. The demos are live, so try them with your keyboard (use Tab, Enter and Space) and, if you can, a screen reader. Then read what changed and why it matters.
What else is on this site
Visible focus indicators
Keyboard users need to see where they are. Removing the focus outline leaves them lost.
WCAG 2.4.7 Focus Visible (AA) Β· 2.4.13 Focus Appearance (AAA)β Inaccessible
Press Tab through these. Can you tell which one is focused?
outline: none with no replacement hides focus entirely.
β Accessible
Press Tab and a clear ring follows you.
A high-contrast :focus-visible ring keeps every control discoverable.
Show the code
β Avoid CSS
button:focus {
outline: none;
}
Hides the focus ring for every keyboard user.
β Better CSS
button:focus-visible {
outline: 3px solid #1a73e8;
outline-offset: 2px;
}
A high-contrast ring, shown only when navigating by keyboard.
Use real buttons
A styled <div> looks like a button but can't be reached or operated with a keyboard.
β Inaccessible
Try to reach and activate this with the keyboard. You can't.
Cart: 0
A <div onclick> has no role, isn't focusable, and ignores Enter/Space.
β Accessible
Tab to it, press Enter or Space, and it works.
Cart: 0
A native <button> is focusable, announced as a button, and keyboard-operable for free.
Show the code
β Avoid
<div class="btn"
onclick="add()">Add</div>
Not focusable, and it ignores Enter and Space.
β Better
<button type="button"
onclick="add()">Add</button>
Focusable, keyboard-operable and announced as a button.
Labelled fields & clear errors
Placeholders aren't labels, and colour alone can't communicate an error.
WCAG 1.3.1 Β· 3.3.1 Error Identification Β· 3.3.2 Labels Β· 1.4.1 Use of Colourβ Inaccessible
Submit empty. Errors are red-only, with no labels.
No <label>, placeholders vanish on typing, and errors rely on colour with no text.
β Accessible
Submit empty. Errors are announced, with text + icon.
Real labels, aria-describedby errors, a focus-managed summary, and errors shown with an icon rather than colour alone.
Show the code
β Avoid
<input placeholder="Email">
No label, and the placeholder vanishes as soon as you type.
β Better
<label for="email">Email</label>
<input id="email" type="email"
aria-describedby="err">
<span id="err">Enter a valid email.</span>
Real label, and the error is tied to the field with aria-describedby.
Sufficient colour contrast
Low-contrast text is hard to read in sunlight, on cheap screens, or with low vision.
WCAG 1.4.3 Contrast (Minimum): 4.5:1 for body textβ Inaccessible
Subscribe to our newsletter for weekly tips and updates.
Contrast β 1.3:1, failsLight-grey text on a grey card is decorative at best and unreadable for many.
β Accessible
Subscribe to our newsletter for weekly tips and updates.
Contrast β 15.8:1, passes AAADark text on a light surface clears AA (4.5:1) comfortably and stays legible everywhere.
Show the code
β Avoid CSS
.note {
color: #a3a3a3; /* on #8e8e8e */
} /* β 1.3:1, fails */
Light grey on grey is unreadable for many.
β Better CSS
.note {
color: #1a1a1a; /* on #f4f4f0 */
} /* β 15.8:1, passes */
Dark on light clears AA (4.5:1) with room to spare.
Meaningful alt text
Screen readers read alt aloud. Missing or junk alt text leaves blind users guessing.
β Inaccessible
A screen reader announces:
"image 4F7A9C.jpg"
No alt falls back to the filename. An alt="image" is just noise.
β Accessible
A screen reader announces:
"Aerial view of a Maldivian island with turquoise lagoon"
Describe the purpose. Purely decorative images get alt="" so they're skipped.
Show the code
β Avoid
<img src="island.jpg">
With no alt, a screen reader reads the filename out loud.
β Better
<img src="island.jpg"
alt="Aerial view of a Maldivian
island and turquoise lagoon">
Describe the purpose. Decorative images get alt="".
Large enough touch targets
Tiny, crowded controls are hard to tap, especially with tremors or large fingers.
WCAG 2.5.8 Target Size (Minimum): at least 24Γ24px, ideally 44Γ44pxβ Inaccessible
Try tapping just one icon on a phone.
~20px targets with no spacing cause mis-taps and frustration.
β Accessible
Comfortable to hit, first time.
44Γ44px targets with spacing are easy and forgiving for everyone.
Show the code
β Avoid CSS
.icon-btn {
width: 20px;
height: 20px;
}
~20px targets cause mis-taps.
β Better CSS
.icon-btn {
min-width: 44px;
min-height: 44px;
}
44Γ44px (min 24Γ24 for WCAG 2.5.8 AA) is easy to hit.
Descriptive link text
Many people skim by jumping link to link. "Click here" out of context says nothing.
WCAG 2.4.4 Link Purpose (In Context)β Inaccessible
A screen reader's "list of links" would read:
Three identical, meaningless links. Out of context, none tell you where they go.
β Accessible
The same list, now self-explanatory:
The link text alone makes the destination obvious, with no surrounding sentence required.
Show the code
β Avoid
<a href="/report.pdf">click here</a>
Meaningless out of context, e.g. in a links list.
β Better
<a href="/report.pdf">
Download the 2025 report (PDF)
</a>
The link text alone says where it goes.
Logical heading structure
Screen-reader users navigate by headings. Skipped levels or fake "headings" break that map.
WCAG 1.3.1 Info & Relationships Β· 2.4.6 Headings & Labelsβ Inaccessible
Bold text that only looks like headings:
Our Services
Web Audits
Training
A styled <p> carries no heading role and is invisible to heading navigation. Jumping from level 1 to 3 also skips a level.
β Accessible
Real, properly nested headings:
h2 Our Services
h3 Web Audits
h3 Training
Convey structure with real headings: nest h2 β h3 in order without skipping levels, and style them with CSS. Never pick a tag for its size. A single h1 for the page's main topic is a solid convention (multiple h1s aren't an automatic failure, but one is easier to reason about).
Show the code
β Avoid
<p class="title">Our services</p>
<p class="sub">Web audits</p>
Styled paragraphs carry no heading role.
β Better
<h2>Our services</h2>
<h3>Web audits</h3>
Real, properly nested headings, styled with CSS rather than tag size.
Name your icon-only buttons
An icon button with no text leaves a screen reader with nothing to announce but "button".
WCAG 4.1.2 Name, Role, Value Β· 1.1.1 Non-text Contentβ Inaccessible
Announced as:
"button β¦ button β¦ button"
The emoji is decorative to the accessibility tree, so each control is just an unnamed "button".
β Accessible
Announced as:
"Search, button β¦ Notifications, button β¦ Settings, button"
An aria-label (or visually-hidden text) gives each button a clear, spoken name.
Show the code
β Avoid
<button>π</button>
Announced only as βbuttonβ.
β Better
<button aria-label="Search">π</button>
aria-label gives the icon button a spoken name.
Modal dialogs & focus management
A real dialog traps focus, closes on Esc, and returns focus when dismissed.
WCAG 2.4.3 Focus Order Β· 2.1.2 No Keyboard Trap Β· 1.3.1β Inaccessible
Open it, then press Tab. Focus drifts to the page behind.
A plain <div> overlay has no dialog role, doesn't trap or restore focus, and ignores Esc.
β Accessible
Open it and focus moves inside, Esc closes, focus returns.
The native <dialog> element handles focus trapping, Esc, and focus return for you.
Show the code
β Avoid
<div class="overlay" id="m">β¦</div>
open.onclick = () =>
m.style.display = "block";
No focus trap, no Esc, focus lost on close.
β Better
<dialog id="m">β¦</dialog>
open.onclick = () =>
m.showModal();
The native <dialog> traps focus, handles Esc and restores focus.
Subscribe?
Notice how Tab still reaches the page behind this overlay.
? Why it is worth doing
Ten fixes is the easy part. The harder part is the meeting where somebody asks how many of your users are really disabled. This is the answer, and it is the same answer that got dropped kerbs built in the first place.
Things built for a specific disabled need keep turning out to serve everybody. Captions, voice control, dark mode and predictive text all arrived the same way. Part 1 of the course makes the whole case, with the numbers.
βΆ Test it yourself
You don't need fancy tools to catch most issues. Start here, then work through the full testing guide when you want the screen reader keystrokes and a record sheet:
β¨οΈ Unplug your mouse
Navigate the whole page with Tab, Shift+Tab, Enter, Space and arrow keys. Can you reach and use everything? Can you always see focus?
π Turn on a screen reader
VoiceOver (β+F5 on Mac) or NVDA (free, Windows). Close your eyes and listen. Does it make sense?
π Zoom to 200%
Press Ctrl/β + a few times. Does content reflow without horizontal scrolling or clipping?
π§ͺ Run axe DevTools (opens in a new tab)
A free browser extension that catches many issues automatically. Great first pass, but no tool replaces manual testing.
Want the whole method? Part 4 of the team training covers a fifteen minute pass, keyboard testing, real NVDA, VoiceOver and TalkBack keystrokes, what automated tools miss, and how to write a finding up.
How to test what you build ββ Where to go next
The lessons above are the hands-on part. These go wider and deeper.
π The whole course
What each of the four parts covers, how long each takes, and a shape for running them with a team.
π Foundations
What accessibility means, universal design and its seven principles, and reasonable accommodation. The concepts behind everything else.
ποΈ Standards explained
WCAG, ARIA, EN 301 549, the ISO series, ADA, the EAA and the CRPD, plus how they all fit together.
π Measuring on site
Ramp slopes, how to measure them properly, key building dimensions and a physical audit method.
π§ͺ Testing what you build
A fifteen minute pass on any page, keyboard and screen reader testing with the real keystrokes, and how to write a finding up.
π Every WCAG criterion
All 86 of them in plain words, with how to check each one. Filter by level, search it, or link straight to a single criterion.
βοΈ The law, country by country
23 laws and standards across 19 jurisdictions, what each one covers, which WCAG version it points at, and the dates that matter.
π The glossary
102 terms in plain language, each with a real example and a link to the page that explains it properly.
π§ Take the quiz
Twenty-seven questions across five topics, with instant feedback, to see what actually stuck.