![Rob Dodson](https://web.dev/images/authors/robdodson.jpg) Rob Dodson [X](https://twitter.com/rob_dodson) [GitHub](https://github.com/robdodson) [Homepage](https://robdodson.me)

<br />

> [!IMPORTANT]
> **Important:** We recommend taking the [Learn Accessibility](https://web.dev/learn/accessibility.md.txt) course to review three different types of testing: automated, manual, and Assistive Technology testing.

[Video](https://www.youtube.com/watch?v=cOmehxAU_4s)

Determining whether your website or application is accessible can seem like an
overwhelming task. If you're approaching accessibility for the first time, the
sheer breadth of the topic can leave you wondering where to start. After all,
working to accommodate a diverse range of abilities means there are a
correspondingly diverse range of issues to consider.

This post breaks down these issues into a logical, step-by-step process for
reviewing an existing site for accessibility.

## Start with the keyboard

For users who either can't or choose not to use a mouse, keyboard navigation is
the primary means of reaching everything on screen. This audience includes
users with motor impairments, such as a repetitive stress injury (RSI) or
paralysis, as well as screen reader users.

For a good keyboard experience, aim to have a logical tab order and clearly
discernible focus styles.

- Start by tabbing through your site. The order in which elements are focused
  should follow the DOM order. If you're unsure which elements should receive
  focus, consult the [module in the Learn Accessibility course about focus](https://web.dev/learn/accessibility/focus.md.txt). The best
  practice is that any control a user can interact with or provide input to
  should be focusable and display a focus indicator (such as a focus ring).

  > [!CAUTION]
  > **Caution:** Avoid using `outline: none` in your CSS to disable focus styles. This is common practice, but if you don't provide an alternative, keyboard users have no way to tell what element is focused and can't interact with your page. To differentiate between mouse and keyboard focus for styling, consider adding a library like [what-input](https://github.com/ten1seven/what-input).

- Custom interactive controls should be focusable. If you use JavaScript to turn
  a `<div>` into a fancy drop-down, it won't automatically be inserted into the
  tab order. To make a custom control focusable, give it a `tabindex="0"`.
  `tabindex` values greater than 0 change the tab order and can be confusing for
  screen reader users.

- Make only interactive content focusable. Adding `tabindex` to non-
  interactive elements like headings slows down keyboard users who can see the
  screen, and doesn't help screen reader users because the screen reader
  already knows to announce them.

- If you add new content to a page, direct the user's focus to that content
  first so they can take action on it. See
  [Managing Focus at the Page Level](https://web.dev/articles/using-tabindex.md.txt#managing_focus_at_the_page_level)
  for examples.

- Design your site so that the user can always focus the next element when they
  want to. Beware of autocomplete widgets and other contexts that can trap
  keyboard focus. You can temporarily trap focus when you want the user to
  interact with a modal and not the rest of the page, but you should always
  provide a keyboard-accessible way to escape the modal. See
  [Modals and Keyboard Traps](https://web.dev/articles/using-tabindex.md.txt#modals_and_keyboard_traps)
  for an example.

### Make your focus control usable

If you've built a custom control, let your users reach *all* of its features
using only the keyboard. Read
[Managing Focus In Components](https://developers.google.com/web/fundamentals/accessibility/focus/using-tabindex#managing_focus_in_components)
for techniques to improve keyboard access.

### Manage offscreen content

Many sites have offscreen content that is present in the DOM but not visible,
like links inside a responsive drawer menu or a button inside a modal window
that hasn't been displayed yet. Leaving these elements in the DOM can create a
confusing keyboarding experience, especially for screen readers, which
announce the offscreen content as if it's part of the page.

See [Handling offscreen content](https://web.dev/articles/dom-order-matters.md.txt#offscreen_content)
for tips to handle these elements.

## Test with a screen reader

Improving general keyboard support lays some groundwork for the next step, which
is to check the page for proper labeling and semantics and any obstructions to
screen reader navigation.

If you're unfamiliar with how semantic markup gets interpreted by assistive
technology, read [Content structure](https://web.dev/learn/accessibility/structure.md.txt).

- Check all images for proper `alt` text. The exception to this practice is when images are primarily for presentation purposes and aren't essential pieces of content. To signify that screen readers should skip an image, set the value to an empty string: `alt=""`.
- Check all controls for a label. For custom controls, this might require the use of `aria-label` or `aria-labelledby`. See [ARIA Labels and Relationships](https://web.dev/articles/aria-labels-and-relationships.md.txt) for examples.
- Check all custom controls for an appropriate `role` and any required ARIA attributes that communicate their state. For example, a custom checkbox needs a `role="checkbox"` and `aria-checked="true|false"` to properly convey its state. See [Introduction to ARIA](https://web.dev/articles/semantics-aria.md.txt) for a general overview of how ARIA can provide missing semantics for custom controls.
- Make the flow of information through your page make sense. Because screen readers navigate the page in DOM order, they'll announce any elements you've visually repositioned visually using CSS in a nonsensical order. If you need something to appear earlier in the page, physically move it earlier in the DOM.
- Aim to support screen reader navigation for all content on the page. Ensure no sections of the site are permanently hidden or blocked from screen reader access.
  - If content *should* be hidden from a screen reader, for example, if it's offscreen or just presentational, set that content to `aria-hidden="true"`. For a deeper explanation, refer to [Hiding content](https://web.dev/articles/hiding-and-updating-content.md.txt#aria-hidden).

### Get familiar with screen readers

Though it might seem daunting to learn a screen reader, they're actually pretty
user-friendly. In general, most developers can get by with just a few simple
key commands.

If you're on a Mac, check out this video about
[VoiceOver](https://www.youtube.com/watch?v=5R-6WvAihms&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=6),
the screen reader that comes with Mac OS. If you're on a PC, check out this
video about [NVDA](https://www.youtube.com/watch?v=Jao3s_CwdRU&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=4),
a donation supported, open-source screen reader for Windows.

### `aria-hidden` doesn't prevent keyboard focus

It's important to understand that ARIA can only affect the *semantics* of an
element; it has no effect on the *behavior* of the element. You can make
an element hidden to screen readers with `aria-hidden="true"`, but that doesn't
change the focus behavior for that element. For offscreen interactive content,
For offscreen interactive content, use [the `inert` attribute](https://web.dev/blog/baseline2023.md.txt#the_inert_attribute)
to make sure it's truly removed from the keyboard flow. For older browsers,
combine `aria-hidden="true"` with `tabindex="-1"`.

## Interactive elements should indicate their purpose and state

Providing visual hints, or *affordances*, about what a control will do helps
a wide variety of people on a wide variety of devices operate and navigate your
site.

- Interactive elements, like links and buttons, should be distinguishable from non-interactive elements. It's hard for users to navigate a site or app when they can't tell if an element is clickable. There are many valid ways to indicate interactive elements. One common practice is underlining links to differentiate them from their surrounding text.
- Similar to the focus requirement, interactive elements like links and buttons require a `hover` state to tell mouse users when their pointer is over something clickable. However, to make these elements accessible to other input methods, they have to be distinguishable without a `hover` state.

## Take advantage of headings and landmarks

Headings and landmark elements give your page semantic structure, and
greatly increase the navigating efficiency of assistive technology users. Many
screen reader users report that, when they first land on an unfamiliar page,
they typically try to
[navigate by headings](http://www.heydonworks.com/article/responses-to-the-screen-reader-strategy-survey).

Similarly, screen readers also offer the ability to jump to important landmarks
like `<main>` and `<nav>`. For these reasons it's important to consider how the
structure of your page can be used to guide the user's experience.

- Use the `h1-h6` hierarchy. Think of headings as tools to create an outline for your page. Don't rely on the built-in styling of headings. Instead, treat them as if they were all the same size and use the semantically appropriate level for primary, secondary, and tertiary content. Then use CSS to make the headings match your design.
- Use landmark elements and roles so users can bypass repetitive content. Many assistive technologies provide shortcuts to jump to specific parts of the page, such as those defined by `<main>` or `<nav>` elements. These elements have implicit landmark roles. You can also use the ARIA `role` attribute to explicitly define regions on the page, as in `<div role="search">`. See [Semantics and navigating content](https://web.dev/articles/navigating-content.md.txt) for more examples.
- Avoid `role="application"` unless you have experience working with it. The `application` landmark role tells assistive technology to disable its shortcuts and pass through all key presses to the page. This means the keys screen reader users typically use to move around the page no longer work, and you'll need to implement *all* keyboard handling yourself.

### Review headings and landmarks with a screen reader

Screen readers, like VoiceOver and NVDA, provide a context menu for skipping to
important regions on the page. When testing for accessibility, you can use
these menus to get an overview of the page and determine if your heading
levels are appropriate and which landmarks are in use.

To learn more, refer to these instructional videos on the basics of
[VoiceOver](https://www.youtube.com/watch?v=5R-6WvAihms&index=6&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g)
and
[NVDA](https://www.youtube.com/watch?v=Jao3s_CwdRU&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=4).

## Automate the process

Manually testing a site for accessibility can be tedious and error-prone.
It's beneficial to [automate testing](https://web.dev/learn/accessibility/test-automated.md.txt) as
much as possible. You can use browser extensions and command line accessibility
test suites.

- Does the page pass all the tests from either the [aXe](https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd) or [WAVE](https://chrome.google.com/webstore/detail/wave-evaluation-tool/jbbplnpkjmmeebjpijfedlgcdilocofh) browser extensions? There are other options available, but these extensions can be a useful addition to any manual test process because they can pick up on subtle issues like failing contrast ratios and missing ARIA attributes.
  - If you prefer to work on the command line, [axe-cli](https://github.com/dequelabs/axe-cli) provides the same features as the aXe browser extension, but can be run from your terminal.
- To avoid regressions, especially in a continuous integration environment, incorporate a library like [axe-core](https://github.com/dequelabs/axe-core) into your automated test suite. axe-core is the same engine that powers the aXe Chrome extension, but in a command line utility.
- If you're using a framework or library, does it provide its own accessibility tools? For example, the [protractor-accessibility-plugin](https://github.com/angular/protractor-accessibility-plugin/) for Angular. Take advantage of available tools whenever possible.

### Use Lighthouse to test PWAs

[Lighthouse](https://developer.chrome.com/docs/lighthouse) is a tool that
measures the performance of your progressive web app (PWA).
And, it uses the axe-core library to power its accessibility tests.

If you already use Lighthouse, look for failing accessibility
tests in your report. Fix the errors to improve the overall user experience of
your site.

## Additional resources

- [Learn Accessibility](https://web.dev/learn/accessibility.md.txt)
- [Web Accessibility by Google](https://bit.ly/web-a11y)