Test code for accessibility compliance
Through a combination of automated and manual techniques, testing for WCAG compliance ensures our implementation meets established accessibility standards as outlined in WCAG
Automated testing tools are able to catch basic structural issues such as missing alt text, improper heading order, low color contrast ratio, and ARIA misuse. Integrating these tools into CI/CD pipelines allows teams to catch many accessibility issues early.
However, most accessibility issues are invisible to automated tools. Context-dependent factors require human judgment, like relevance of alt texts and readability of written content. Manual testing is essential for evaluating cognitive load, keyboard navigation, focus states, error message content, and overall usability.
In most cases, it is best practice to involve assistive technology experts to ensure content is understandable on screen readers. Most people who do not use screen readers in their day-to-day won't be able to definitively say content is screen reader accessible. Overall, including people with many types of disabilities in the testing process can help confirm that the experience is functional beyond just technical compliance.
What am I responsible for testing?
At present, the majority of contracts with U.S. based organizations establish W3C WCAG 2.2 Level AA as the standard by which websites are considered compliant. WCAG can be complex in language, and it is not always reasonable to expect every individual contributor have this specification memorized. However, every person writing code should include basic manual accessibility testing into their pre-merge request process.
Web accessibility practitioners should understand how to follow WCAG 2.2 guidelines. This does not necessarily include navigating the web with assistive technology. As accessibility practitioners, our duty to our clients and users can be summarized in three points:
-
Manual testing with an eye for accessibility. Understanding the basics of accessibility specification and testing our own code as we write it.
-
Automated testing with a skeptical outlook. Leveraging automated testing tools while also understanding these tools are not perfect and will miss things.
-
Referral to experts when it matters. When a user base is likely to include many members with specific needs, or if the purpose of the code is an important function, accessibility and assistive technology experts should be consulted. For example, a website that supports a basic necessity like paying for electricity, or if it provides a service like captioned videos for students who are Deaf or have other auditory disabilities.
How do I manually test my own code for accessibility violations?
Combined with automated testing and working with accessibility specialists, the following practices help keep our websites compliant.
Follow POUR
"POUR" stands for Perceivable, Operable, Understandable, and Robust. These four principles are what guides WCAG's specification. We can likewise use them to guide our testing process. Review your changes with them in mind by walking through the following mental framework.
1. Look at the page. Is everything perceivable?
- Does anything on the page look too small or lacking in contrast?
- Do all of my images have alt text attributes? Do the decorative images have empty alt text?
- Do headings make sense?
- Do inputs have labels?
- Are there pictures of text or data, such as a chart or diagram, that needs an alternative?
- Can I zoom the page to 400%?
- Does anything need both a horizontal and vertical scroll to see?
2. Navigate the page. Is everything operable?
- Can I get through everything with my keyboard? Can I open and close menus? Are there bypass blocks?
- Does the page have a title attribute? And landmarks, e.g. header, footer, main?
- Can I pause animations and video that play more than 3 seconds? Do I have any sounds that autoplay?
- Have I looked at the page on all screen sizes?
- Are buttons big enough to click?
- Do all of my links have unique, quality text?
- Are there any complicated interface elements that need alternatives? Carousels, sliders, drag and drop?
3. Read the page. Is everything understandable?
- Am I using any complicated words or abbreviations that I could define, change, or link to?
- Are my menus consistent across pages? Are headings? Links? Breadcrumbs?
- Do all of my interactive elements (buttons, links, etc) have both focus states and hover states that are not only a color change?
- Do all of my inputs have error messages?
- Have I used semantic HTML to make elements autocomplete?
- Did I provide content alternatives where possible?
4. Check everything one more time. Is this page robust?
- Did I follow common patterns that I can trust will fail elegantly?
- Do all of my elements use the correct roles or semantic html tags?
- Did I check the accessibility tree?
- Did I look at this in a second browser or on a phone screen?
5. Run a browser-based checker
In addition to reviewing POUR concepts, a good browser extension tool such as Axe DevTools or WAVE can help you identify accessibility violations in web UI. These tools often check for color contrast, valid html, missing labels or attributes, and ARIA best practices. Before submitting a PR, take a look at what your favorite tool says.
How do I manually test with a screen reader?
It's relatively simple to set up a screen reader and turn it on, but there's a high degree of skill involved in navigating the world with a screen reader. Don't get overwhelmed if you find it difficult at first - it takes time and practice, and you can accomplish a lot with a basic understanding of how to use a screen reader.
What should I test for?
There are generally two kinds of problems you'll encounter as a screen reader user:
Content that is "invisible" to the screen reader
If content is invisible to the screen reader, it means that screen reader users won't be able to access it at all.
This can include things like:
- Images without alt text: If an image doesn't have alt text, screen reader users won't know what the image is or what information it conveys.
- Form fields that aren't associated with labels: Without a label, screen reader users don't know what information to enter into a form field.
- Modal windows that aren't properly labeled: If a modal window doesn't have a proper label, screen reader users won't know what the modal is for or how to interact with it.
Content that is "visible" to the screen reader, but is difficult to navigate or understand
Screen reader users will technically be able to access this content, but it might take a lot of effort to navigate and understand it. Screen reader users "jump around" a lot, just like sighted users do. Web pages often contain a lot of content, like dropdown menu structures, sidebars, and other things that sighted users can easily skip over. Screen reader users do the same thing, but they rely on the HTML structure and labels to understand the hierarchy of the page and identify where they're trying to go. If the HTML structure is confusing or doesn't match the visual hierarchy, screen reader users might "jump past" the content they need.
This category of problems can include things like:
- Broken linear flow: If the tab or HTML order of a page doesn't match the visual order, screen reader users might end up in a different place than they expect when they hit the tab or arrow key. This can be particularly problematic for forms, where users expect to tab through fields in a specific order.
- Missing hierarchical context: Especially in forms that contain visually nested groups, if the HTML structure doesn't make the hierarchy clear, it's easy for a screen reader user to miss that the "Birth Date" field is part of the "Dependent Information" section, and not part of the "Personal Information" section.
- Missing content context: For example, buttons simply labelled "Submit" or links that say "Click here" don't provide any context about what the button or link does, which means a screen reader user needs to read all of the surrounding content to understand what it does. This is particularly problematic when links or buttons are in separate HTML structures from the content they relate to.
- Focus traps: Modal windows are hard to get right - without taking particular care, it's easy for users to "escape" the modal by tabbing past the last element and end up on a section of the page they didn't intend to be on. It's also easy for users to completely lose focus when a modal closes, and end up somewhere else on the page than they were before.
In General
Your goal as a tester is to ensure that your content is both visible and understandable when navigated with a screen reader. While there are general patterns of errors (like missing alt text) you can pick up using automated accessibility testing tools, the only real way to know if your content is accessible is to test it using a screen reader and see if you can understand it.
Which screen reader should I use?
Screen readers have different features and quirks just like browsers. According to WebAIM's screen reader survey, the most popular screen readers are NVDA, JAWS, and VoiceOver. Unfortunately, screen readers are only half of the equation - you'll also need to consider the user's browser, which may have quirks of its own. You'll get the most realistic testing if you follow the most common pairings noted in WebAIM's survey (eg: on Windows use NVDA+Chrome, on Mac use VoiceOver+Safari).
For an accessibility novice with a goal of basic testing, we recommend starting with the following options, depending on your operating system:
Despite the popularity of JAWS, the fact that is a paid product makes it not a good choice for someone just starting out with screen reader testing.
As your skills grow, it can be helpful to test with multiple screen readers to catch any issues that may be specific to a particular screen reader. That being said, if you're just starting out, it's perfectly fine to stick with one screen reader and become proficient with it before branching out to others.
How do I test with a screen reader?
Once you have a screen reader set up, you can start testing your content. The exact steps will depend on the screen reader you're using, but in general, you'll want to test the following:
- Readout: Don't look at the page. Use the screen reader's navigation tools to try to understand the content. Can you accomplish the same tasks as a sighted user?
- Tab order: Use the tab key to navigate through the page. Does the focus move in a logical order that matches the visual hierarchy of the page?
- Rotor menu: If your screen reader has a rotor menu (like VoiceOver) or an elements list (like NVDA), open it and use it to jump to specific sections on the page. Does the rotor menu accurately reflect the structure of the page? Can you easily find the different sections of the page and understand their hierarchy?
When you're just getting started with a screen reader, it's best to focus on these simple navigation and readout tasks. If you need to test more complex elements, such as modals or dropdown menus, it's a good idea to call in someone with more experience and shadow them as they test - these elements are particularly tricky to get right, and it can be helpful to see how an experienced screen reader user interacts with them.
Automate accessibility tests
Many, but not all, categories of accessibility issues are easily detectable with automated tools. By integrating accessibility tests into the CI/CD pipeline, teams can catch simple issues early and reserve human testing effort for more complex problems that require context and judgment. Automated tools can also be used to quickly check for regressions in accessibility as code changes over time.
There are a lot of tools out there, but most of them are built on top of the same underlying accessibility testing engine, which is aXe. aXe provides a comprehensive set of rules for detecting accessibility issues in web content.
Integrating aXe into unit tests
Unit tests are the right choice for comprehensively testing a single component or page. By testing at the component level, you can also verify that every state of a particular component is accessible, which can be difficult to do any other way.
We recommend jest-axe and vitest-axe for Javascript testing libraries, depending on which testing framework you're using. Both of these libraries wrap axe-core and provide a simple API for running accessibility tests in your unit tests. Here's a quick example of how to use jest-axe in a React component test:
import {it, expect} from "vitest";
import {render} from "@testing-library/react";
import {axe} from "vitest-axe";
it("should have no accessibility violations in its default state", async () => {
const {container} = render(<Alert message="there was a problem" />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it("Should have no accessibility violations when the alert is open", async () => {
const {container} = render(<Alert message="there was a problem" open />);
const results = await axe(container);
expect(results).toHaveNoViolations();
}); Integrating aXe into end-to-end tests
While unit tests offer deep coverage of individual component states, you also want to ensure that the overall user experience is accessible, and the final HTML is assembled in a logical way. End-to-end tests are the right choice for this, and allow you to check accessibility in a broad (but not deep) way.
We recommend @axe-core/playwright for end-to-end testing. This library provides a simple API for running accessibility tests in your end-to-end tests. Here's a quick example of how to use @axe-core/playwright in a Playwright test:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test.describe("homepage", () => {
test("should not have any automatically detectable accessibility issues", async ({
page,
}) => {
await page.goto("https://example.com/");
const accessibilityScanResults = await new AxeBuilder({ page }).analyze(); // 4
expect(accessibilityScanResults.violations).toEqual([]); // 5
});
}); An even better way to use @axe-core/playwright is to integrate page-level checks into your existing end-to-end tests. This way, you can avoid writing separate tests just for accessibility, and you can also ensure that you're focusing testing on the pages that are most important for your application.
Use testing-library, and follow their guidance on selector priority
While not strictly an accessibility testing tool, testing-library for Javascript is a popular testing framework that encourages good testing practices. Good testing practices overlap a lot with good accessibility practices, so we recommend using testing-library for your unit and end-to-end tests. You should use it for React or HTML testing. From their website:
It should be generally useful for testing the application components in the way the user would use it. We are making some trade-offs here because we're using a computer and often a simulated browser environment, but in general, utilities should encourage tests that use the components the way they're intended to be used.
Practically, this means picking query selectors that reflect how users (including users with disabilities) interact with the page, rather than picking selectors that reflect how the page is implemented. They have given specific guidance on selector priority. Following this guidance will go a long way toward testing for accessibility, since it requires you to structure your HTML in an accessible way and use labels and roles effectively.
For example, a quick takeaway from their guidance is to prefer queries that reflect how users interact with the page, such as getByRole, getByLabelText, and getByText, rather than queries that rely on implementation details, such as getByTestId or getByClassName.
Automating with CI/CD
If you use the guidance above, you shouldn't need to do anything special in CI/CD. You're already running unit and End-to-End tests, and preventing PR merge if they fail, right? By using these three techniques, you can get accessibility coverage in your CI/CD pipeline without any additional setup.
What are common development mistakes I can avoid?
There are an almost endless array of requirements and guidelines to follow when committing code. As we grow, some of these patterns become instinctive. Accessibility should also become second nature and with practice, it can. To start, here are some easy mistakes to avoid when pushing frontend code.
Using <div> for Everything
As engineers, we may be tempted to use <div> elements for every block of content we create. It makes sense, especially when quickly prototyping a web page. Unfortunately, this practice can make our websites incredibly frustrating to navigate for users who rely on assistive technology.
Screen readers are one type of assistive technology that rely on the semantics and structure of a web page to relay its content to users. When designing a web page, we add visual affordances that communicate to sighted users how elements behave, for example, color, contrast and drop shadows. Users who can't see our page lose those cues entirely. This means that the semantics we provide in HTML become their primary way of interacting with our content, which they do through a screen reader.
HTML provides a rich collection of semantic elements we can take advantage of when designing pages. You might already be familiar with some, such as <header>, <nav>, and <main> — but there are many more to choose from. See MDN's HTML elements reference for a full list.
These semantic elements work with screen readers out of the box, meaning the more structured we make our markup, the easier it becomes for users to navigate our application. A small change for engineers can make a world of difference for users who rely on screen readers.
Instead of:
<div class="header">Site Title</div>
<div class="nav">...</div>
<div class="main">Main content</div> Try:
<header>Site Title</header>
<nav>...</nav>
<main>Main content</main> Using Raw Color Values
If you are working on a large web application, it is likely that your team is using a design system. An easy habit to fall into is reaching for raw hex color codes when implementing features. The danger here — beyond poking the bear of the design team — is that raw values can't adapt to core design changes, and they may produce content with poor contrast.
Our content should have sufficient contrast so that users with reduced vision can more easily understand our pages. Contrast is measured using the contrast ratio, which can be calculated with tools like WebAIM's Contrast Checker. WCAG recommends a minimum ratio of 4.5:1 for normal text and 3:1 for large text.
Instead of:
.button {
background: #3498db;
color: #fff;
} Try:
.button {
background: var(--color-primary);
color: var(--color-on-primary);
} Next time you're about to type a hex code, look for a color variable or token that has already been defined in your design system!
Missing or Inadequate Alt Text
Whenever you insert an image using an <img /> element or a framework's <Image /> component, make sure to add meaningful alternative text (alt). Many editors will warn you when the alt attribute is missing, and it can be tempting to fill it in with something like "img" or "picture" just to clear the warning. Resist that urge.
Alternative text serves two important purposes:
- Accessibility: Visitors who are blind or have low vision rely on screen readers to read alt text aloud in place of images.
- SEO: Descriptive alt text improves how search engines index your content.
Here are some tips for writing effective alt text:
- Focus on the purpose of the image. How does it support the surrounding content?
- Use full sentences and proper grammar.
- Be concise and don't over-describe.
Instead of:
<img src="dog.png" alt="dog" /> Try:
<img
src="dog.png"
alt="A golden retriever wearing sunglasses and riding a skateboard"
/> This one requires a bit more thought, but the payoff is worth it. See this Google article on writing effective alt text if you want to go deeper. There is one exception to this rule, however, and that is decorative images that don't serve an informational purpose. For these, you should set the alt text to <img alt="" /> which will inform the assistive technology that this image can be skipped.
Misusing ARIA
Accessible Rich Internet Applications (ARIA) is designed to supplement HTML as a bridge between code and assistive technologies — filling in accessibility gaps where native HTML falls short. If you're already using semantic HTML properly, it is usually not necessary to include ARIA roles or attributes in your markup.
According to reports from WebAIM, the number of ARIA attributes per home page has been increasing over time and unfortunately, this increase is associated with more errors. In fact, pages with ARIA present had more accessibility errors on average than pages without it. This has led to a widely shared principle:
No ARIA is better than bad ARIA.
So what's going wrong? Semantic HTML informs assistive technology of an element's behavior and purpose out of the box. While that is the ideal scenario, there are cases where you need to explicitly tell assistive technology how to interpret an element, and that's where ARIA comes in.
A simple example: a <button> containing an SVG icon (like a "+" sign) with no text. A screen reader won't know what to call it, so you'd add aria-label="Add item" to give it a name.
<button aria-label="Add item">
<svg><!-- icon --></svg>
</button> If this button had action text, you wouldn't apply role or aria-label attributes because the <button> element does that automatically!
Instead of:
<button role="button" aria-label="Click me">Click me</button> Try:
<button>Click me</button> Another example: skeleton loaders and placeholder content seem to be trending. This content is unfamiliar to screen readers and users may be confused about what's going on. In this case you can add:
aria-busy="true"signals that content is still loading.aria-labeldescribes what the placeholder content represents.
Before reaching for ARIA, first check whether a semantic HTML element already exhibits the behavior you need. If one exists, use it. If not, consult the MDN ARIA documentation for the appropriate attributes.
Going Too Small on Mobile
On desktop, we typically have plenty of screen real estate to work with — sidebars, navbars, toolbars, you name it. But according to Statista, mobile users account for more than half of all web traffic, making mobile responsiveness a top priority.
One common mistake when building for phones is making elements too small in order to fit more content on the screen. While this isn't tied to a single disability, a website that's difficult to navigate or interact with on mobile may be deterring over 50% of your users from getting value out of it.
The WCAG guideline: make touch targets at least 40px wide so users can tap them reliably without frustration. Another good rule of thumb: start with 16px as the base font-size and expect users to zoom in/increase font size using plugins and extensions.
Help us improve
Your feedback helps us create better resources for teams like yours.
Last updated on