Study: AudioEye detects up to 2.5x more issues than other tools

Get Report
Blog
Compliance

ADA Compliance for Developers

ADA compliance for developers means writing and testing code that conforms to WCAG 2.2 Level AA, the technical standard that's become the practical benchmark for accessible websites. Learn how to create code that’s accessible and compliant with key accessibility laws.

Author: Jeff Curtis, Sr. Content Manager

Published: 08/06/2026

Stylized laptop with various accessibility icons on the top of the page. The laptop is sitting on top of a closed book.

If you build or maintain a website, compliance with the Americans with Disabilities Act(opens in a new tab) is your problem too, not just legal's. The ADA requires "places of public accommodation" to be accessible to people with disabilities, and courts have extended that requirement to websites and digital products, not just physical spaces like storefronts.

For developers, ADA compliance means writing and testing code that conforms to the Web Content Accessibility Guidelines(opens in a new tab) (WCAG) 2.2 Level AA, the technical standard that's become the practical benchmark for accessible websites in the United States.

This page covers the part of that standard that applies specifically to developers: the actual HTML, ARIA, and keyboard patterns that make a site conform to key accessibility standards and improve the overall experience for users with disabilities.

What is Accessible Code?

Accessible code is front-end markup and scripting that assistive technologies, such as screen readers and keyboard-only navigation, can interpret and operate without extra work from the user. 

In practice, that comes down to four things: semantic HTML that gives elements built-in meaning, ARIA that fills the gaps native HTML can't, keyboard navigation that doesn't trap or skip users, and accessible forms that label and explain themselves.

How Does Semantic HTML Improve Accessibility?

Semantic HTML makes your site accessible automatically, with no extra code. Take a <button> element. It does three things on its own that screen readers and keyboards need: you can tab to it, it responds to Enter and Space, and it announces itself as a "button."

A <div> made to look like a button does none of that. It's just a styled box, so assistive technology has no way to know it can be clicked.

That's the whole idea behind semantic HTML: use the right element for the job, and the browser does the accessibility work for you.

  • Landmark elements like <header>, <nav>, <main>, and <footer> let screen reader users jump straight to a page's main regions instead of tabbing through everything.

  • A clean <h1> to <h6> order, with no skipped levels, gives screen reader users a table of contents they can navigate.

  • Native controls like <button>, <a>, and <input> come with keyboard behavior and screen reader announcements built in, so you don't have to rebuild any of that with a styled <div>.

The difference is easiest to see side by side. Here's the same simple layout built two ways: once with unstyled <div>s standing in for real elements, and once with the elements built for the job:

Before (div soup):

<div class="header">
  <div class="nav">
    <div class="nav-item" onclick="goHome()">Home</div>
    <div class="nav-item" onclick="goProducts()">Products</div>
  </div>
</div>

<div class="main-content">
  <div class="title">Our Products</div>
  <div class="button" onclick="submitForm()">Submit</div>
</div>

Every element here is a plain, unstyled box. Nothing is focusable, nothing responds to a keyboard, and a screen reader announces plain text, not a link or a button.

After (semantic HTML)

<header>
  <nav aria-label="Main">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/products">Products</a></li>
    </ul>
  </nav>
</header>

<main>
  <h1>Our Products</h1>
  <button type="submit">Submit</button>
</main>

Same layout, same visual result, and no ARIA required anywhere. The links are automatically focusable and keyboard-operable, and the button announces itself as "Submit, button" the moment a screen reader reaches it.

A common mistake to be aware of: building a clickable element out of a <div>, like <div onclick="submitForm()">. It may look and even be styled like a button, but to assistive technology, it isn't one. A screen reader won't tell the user it's interactive, a keyboard user can't tab to it, and pressing ‘Enter’ or ‘Space’ does nothing, so anyone not using a mouse is stuck.

The fix is simple: if it acts like a button, make it a <button>. You get the focus, keyboard, and screen reader behavior for free.

When Should You Use ARIA?

Use ARIA (Accessible Rich Internet Applications) only when native HTML cannot express a role, state, or property you need. 

This is the first rule of ARIA: if a native element or attribute already has the semantics and behavior you're after, use that instead of repurposing something else and layering ARIA on top. ARIA changes how assistive technology interprets an element, but it adds none of the keyboard behavior or focus handling that HTML gives you automatically.

ARIA breaks into three pieces, and screen readers announce all three:

Concept

What It Does

Example

Role

Defines what an element is.

role="dialog" tells assistive technology this is a modal dialog

State

Describes the element’s current condition.

aria-expanded="true" means a disclosure is currently open

Property

Describes a relationship to another element.

aria-labelledby="heading-id" points to the element that labels this one

For example, an accordion-style disclosure has no native HTML element. This is where ARIA earns its place.

<button aria-expanded="false" aria-controls="faq-answer-1" id="faq-question-1">
    What is ADA compliance for developers?
</button>

<div id="faq-answer-1" role="region" aria-labelledby="faq-question-1" hidden>
  <p>Answer text goes here.</p>
</div>

const button = document.getElementById('faq-question-1');

const panel = document.getElementById('faq-answer-1');

button.addEventListener('click', () => {
  const expanded = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', String(!expanded));
  panel.hidden = expanded;
});

Look at how the work is divided. The native HTML and ARIA each do a job only they can do.

The <button> is a real button, so it's focusable and keyboard-operable by default, and the hidden attribute controls whether the panel is visible. But native HTML stops there. It has no way to tell a screen reader whether the panel is open or which button controls it, and without that, the accordion is unusable for someone who can't see it. That's the gap ARIA closes: aria-expanded announces the open/closed state, and aria-controls/aria-labelledby tie each button to its panel.

That's the rule for ARIA: let native elements do what they do well, then add ARIA exactly where the semantics fall short, no less than what's needed.

How Do You Make a Site Keyboard Accessible?

A site is keyboard-accessible when every interactive element can be reached and operated using the ‘Tab’, ‘Enter’, ‘Space’, and arrow keys in a logical order, with a visible focus indicator at all times. This matters for anyone who can't or doesn't use a mouse, including screen reader users, switch device users, and people with motor disabilities.

Keyboard accessibility depends on three things:

  1. Logical focus order. Tab order should follow the page's visual and reading order. If you find yourself reaching for a positive ‘tabindex’ value to fix a broken order, fix the underlying markup order instead.

  2. A visible focus indicator. Always. Never remove the default focus outline without replacing it.

  3. Skip links for repeated navigation. Let keyboard users jump past a header and nav straight to the main content.

<a class="skip-link" href="#main-content">Skip to main content</a>

<header>...</header>

<nav>...</nav>

<main id="main-content">

  ...

</main>

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
}

.skip-link:focus {
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 16px;
  z-index: 100;
}

For composite widgets like tab lists or toolbars, use roving tabindex so arrow keys move focus within the widget while Tab moves past it entirely:

tabs.forEach((tab, i) => {
  tab.addEventListener('keydown', (e) => {
    if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;

    e.preventDefault();

    const next = tabs[(i + (e.key === 'ArrowRight' ? 1 : -1) + tabs.length) % tabs.length];

    tabs.forEach(t => (t.tabIndex = -1));
        next.tabIndex = 0;
        next.focus();
  });
});

Another common mistake to avoid is using * { outline: none; } in a global stylesheet. This is one of the most common accessibility failures on the web, and it's usually accidental, left over from a designer disliking the default blue outline. Replace it with a custom :focus-visible style; never delete it outright.

How Do You Build Accessible Forms?

Accessible forms pair every input with a programmatically associated <label>, group related fields with <fieldset> and <legend>, and report errors in text tied to the field with aria-describedby.

<form>
  <fieldset>
    <legend>Contact information</legend>
    <label for="email">Email address</label>
    <input
      type="email"
      id="email"
      name="email"
      required
      autocomplete="email"
      aria-describedby="email-error"
    >
    <span id="email-error" role="alert">Enter a valid email address.</span>
  </fieldset>

  <button type="submit">Submit</button>
</form>

Three things are doing the work here: for/id link the label to the input so a screen reader announces them together, aria-describedby connects the error message to the field it belongs to, and autocomplete lets browsers and assistive technology fill known fields correctly. If you're also checking color contrast on form states like error borders, WCAG 2.2 Level AA requires at least a 4.5:1 color contrast ratio for normal text and 3:1 for large text and UI components.

Stylized web browser with robotic arms moving various elements on the page. The accessibility symbol is in the bottom right-hand corner.

How Do Developers Test for Accessibility?

Developers can test for accessibility using automated checks, manual keyboard-only navigation, and screen reader testing. Automated tools can only catch common accessibility issues (e.g., missing alt text, missing form labels, insufficient contrast, etc.); issues that depend on judgment, like whether alt text is actually descriptive or whether a focus order makes sense, require a person. 

A practical testing process looks like this:

  1. Run an automated scan first to catch common issues quickly and at scale.

  2. Unplug your mouse and navigate the whole page with Tab, Shift + Tab, Enter, Space, and arrow keys. Ensure you can reach everything interactive, in a logical order, with a visible focus indicator throughout.

  3. Test further with a screen reader. VoiceOver on macOS and iOS, NVDA or JAWS on Windows, and TalkBack on Android are the most used assistive technologies. Confirm headings, labels, and states are announced the way you’d expect.

  4. Re-test after any markup change. A refactor that touches the DOM can quietly break something that worked before, like a screen reader announcement or a focus trap, without any visible sign that anything's wrong.

Sometimes testing turns up more issues than your team can fix right away. That's a fix problem, not a testing one, and it needs its own plan for what to tackle first.

Where Do Automation and Expert Testing Fit?

Hand-coding gets you most of the way to an accessible site, but it doesn't scale on its own. The patterns above will make an individual page or component accessible. The harder problem shows up across hundreds of templates, a CMS that generates markup you don't fully control, and content editors who add new pages daily without touching your codebase.

That’s the benefit of using both automation and expert audits: automation catches common, repeatable issues across every page in real time, and expert testers handle the judgment calls automation can’t, like whether a focus order actually makes sense or whether alt text conveys the right information. 

Staying Accessible as Your Site Changes

Getting a page right is the part you can control. You choose the element, you test the focus order, you check the label, and the page in front of you conforms to WCAG 2.2 Level AA requirements. The problem is that a page is not a site.

The accessible page you just shipped sits inside hundreds of templates you didn't write, CMS markup you don't fully control, and new content your team publishes daily without ever touching your codebase. Every deployment is a chance for a regression you won't catch by hand. Accessibility isn't a state you reach once; it's one you have to hold as the site keeps changing.

That's where AudioEye fits, by handling this continuously and inside the workflow you already use. AudioEye combines AI-powered automation with expert human audits: automation handles the volume of repeatable issues across every page in real time. In contrast, expert auditors make the judgment calls automation can't make on its own. 

Our Accessibility Developer Tools also plug directly into your pipeline, so issues surface in pre-production, before they ship. With AudioEye, your developers can be confident that the code they generate is based on accessible patterns, not guesswork.

Start by seeing where your code stands today. Run a free scan of your site, or talk to an expert about connecting to your pipeline.

Frequently Asked Questions

Share Article

Ready to test your site's accessibility?