If you have ever searched how to make a website accessible, you probably found lists of ten tips repeating the same generic advice: add alt text, check contrast, use headings. Useful, but not enough to actually ship an accessible product. This guide is different. It is a developer-focused walkthrough with real code you can paste into your project today, aligned with the current WCAG 2.2 standard.
By the end of this article, you will have a concrete checklist covering semantic HTML, ARIA attributes, keyboard navigation, color contrast, and focus management. Let’s get to work.
Why Web Accessibility Matters in 2026
Accessibility is no longer a nice-to-have. The European Accessibility Act came into force in June 2025, and lawsuits in the US under the ADA continue to rise year over year. Beyond compliance, an accessible website is a better website: cleaner markup, better SEO, better mobile UX, and a wider audience. WCAG 2.2 (the current stable version) added nine new success criteria focused on cognitive accessibility, mobile touch targets, and dragging alternatives.

The Developer’s WCAG 2.2 Quick Checklist
| Area | Priority | Time to Implement |
|---|---|---|
| Semantic HTML structure | Critical | 1 to 2 hours |
| Keyboard navigation | Critical | 2 to 4 hours |
| Focus management | Critical | 2 hours |
| Color contrast (4.5:1 min) | Critical | 1 hour |
| ARIA attributes (when needed) | High | 2 hours |
| Touch target size (24×24 min WCAG 2.2) | High | 30 minutes |
| Form labels and errors | Critical | 1 to 2 hours |
1. Start with Semantic HTML (Not Divs)
The single biggest accessibility win costs nothing: use the right HTML element for the job. Screen readers, browsers, and assistive tech already know how to handle native elements. Every <div> button you build is a bug waiting to happen.
Bad
<div class="btn" onclick="submit()">Submit</div>
<div class="nav">
<div class="link" onclick="goHome()">Home</div>
</div>
Good
<button type="submit">Submit</button>
<nav aria-label="Main">
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
Use these landmarks on every page:
- <header> for site header
- <nav> for navigation blocks
- <main> for the primary content (only one per page)
- <aside> for tangential content
- <footer> for footer
2. Keyboard Navigation: The 5-Minute Test
Put your mouse away. Can you use your entire site with just Tab, Shift+Tab, Enter, Space, and arrow keys? If not, you have work to do.
Common fixes
- Never use
outline: none;without providing an alternative focus style. - Avoid positive
tabindexvalues. Usetabindex="0"to make something focusable,tabindex="-1"to remove it from tab order but keep it programmatically focusable. - Add a skip link as the first focusable element:
<a href="#main" class="skip-link">Skip to main content</a>
<style>
.skip-link {
position: absolute;
left: -9999px;
}
.skip-link:focus {
left: 1rem;
top: 1rem;
background: #000;
color: #fff;
padding: 0.5rem 1rem;
z-index: 9999;
}
</style>

3. Focus Management for Modals and SPAs
When a modal opens, focus must move inside it. When it closes, focus must return to the trigger. This is where most single-page apps fail.
class Modal {
constructor(element) {
this.modal = element;
this.previouslyFocused = null;
}
open(trigger) {
this.previouslyFocused = trigger || document.activeElement;
this.modal.hidden = false;
this.modal.setAttribute('aria-hidden', 'false');
const firstFocusable = this.modal.querySelector(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
firstFocusable?.focus();
this.modal.addEventListener('keydown', this.trapFocus);
}
close() {
this.modal.hidden = true;
this.modal.setAttribute('aria-hidden', 'true');
this.previouslyFocused?.focus();
this.modal.removeEventListener('keydown', this.trapFocus);
}
trapFocus = (e) => {
if (e.key === 'Escape') this.close();
// Full trap logic: cycle Tab between first and last focusable
}
}
For route changes in a SPA, move focus to the new page’s <h1> or main container so screen reader users know something happened.
4. Color Contrast: The Math That Matters
WCAG 2.2 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18pt+ or 14pt+ bold). For UI components and graphical objects, the minimum is 3:1.
Tools to check contrast
- Chrome DevTools: inspect any element, hover the color swatch, it shows the ratio and a checkmark.
- WebAIM Contrast Checker
- The
color-contrast()CSS function (now supported in modern browsers)
Rule of thumb: never use grey text lighter than #767676 on white, or lighter than #949494 on a light grey background.
5. ARIA: Use Only When You Must
The first rule of ARIA is: don’t use ARIA if a native HTML element does the job. That said, here are the patterns you will actually need:
Accessible names for icon buttons
<button aria-label="Close dialog">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
Live regions for dynamic updates
<div role="status" aria-live="polite">
Item added to cart
</div>
<div role="alert" aria-live="assertive">
Error: Payment failed
</div>
Expandable content
<button aria-expanded="false" aria-controls="menu-1">
Menu
</button>
<ul id="menu-1" hidden>
<li><a href="/products">Products</a></li>
</ul>
6. Forms Done Right
Forms are where accessibility breaks down fastest. Follow this pattern every time:
<div class="field">
<label for="email">Email address</label>
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
aria-describedby="email-hint email-error"
aria-invalid="false"
>
<p id="email-hint">We'll never share your email.</p>
<p id="email-error" role="alert"></p>
</div>
Key points:
- Every input has a real
<label>connected withforandid. - Use
autocompleteattributes (WCAG 2.2 requirement 1.3.5). - Errors are announced via
role="alert". - Toggle
aria-invalidon validation failure.

7. New WCAG 2.2 Criteria You Cannot Skip
Since WCAG 2.2 became the recommended standard, these are the criteria most sites still fail on:
| Criterion | What it means |
|---|---|
| 2.4.11 Focus Not Obscured | Focused elements must not be hidden by sticky headers or cookie banners. |
| 2.5.7 Dragging Movements | Any drag action must have a single-pointer alternative (like buttons). |
| 2.5.8 Target Size Minimum | Interactive targets must be at least 24×24 CSS pixels. |
| 3.3.7 Redundant Entry | Don’t ask users to re-enter info they already provided in the same flow. |
| 3.3.8 Accessible Authentication | No cognitive puzzle tests unless there is an alternative. |
8. Testing: Automate, Then Verify Manually
Automated tools catch about 30 to 40 percent of accessibility issues. You need both. shrm.org has a solid rundown on this.
Automated testing
- axe DevTools browser extension (free)
- Lighthouse in Chrome DevTools
- Pa11y or axe-core in your CI pipeline
Manual testing
- Navigate the entire page with keyboard only.
- Zoom the browser to 200%. Nothing should be cut off or unusable.
- Test with a screen reader: NVDA (free, Windows), VoiceOver (built into macOS and iOS), or TalkBack (Android).
- Check with Windows High Contrast Mode or forced-colors CSS.
The Same-Day Accessibility Checklist
Copy this into your PR template:
- Semantic HTML used, no div buttons
- Page has one h1 and logical heading order
- All images have alt text (or empty alt if decorative)
- All form inputs have visible labels
- Keyboard accessible with visible focus indicator
- Color contrast 4.5:1 minimum for text
- Touch targets at least 24x24px
- Skip link present
- Page tested with axe DevTools, zero critical issues
- Screen reader smoke test performed
FAQ
How long does it take to make a website accessible?
For a small marketing site, retrofitting basic WCAG 2.2 Level AA compliance typically takes 20 to 40 developer hours. Building it in from the start adds roughly 10 to 15 percent to development time and saves multiples of that in remediation later. For a real-world example, look at one agency that does this well.
Is ARIA better than semantic HTML?
No. Native HTML always wins. ARIA is a bridge for cases where HTML falls short (custom components, live updates, complex widgets). Wrong ARIA is worse than no ARIA.
What’s the difference between WCAG 2.1 and WCAG 2.2?
WCAG 2.2 (the current recommendation) adds nine new success criteria on top of 2.1, mostly around cognitive accessibility, mobile interactions, and authentication. If you meet 2.2, you automatically meet 2.1.
Do I need Level AAA compliance?
For most commercial sites, Level AA is the legal and practical target. AAA is often impossible for entire pages and is typically applied selectively to critical content.
Can accessibility overlays make my site compliant?
No. Accessibility overlay widgets have been widely criticized and have been the subject of lawsuits themselves. Real accessibility comes from the code, not a script tag.
Does accessibility help SEO?
Yes. Semantic HTML, descriptive alt text, proper heading structure, and good link text all directly benefit search rankings. Accessibility and SEO share the same foundation: clear, well-structured content.
Ready to ship? Take one page of your site today, run through the checklist above, and fix what you find. Accessibility is not a project you finish. It is a habit you build.

