Web Accessibility


Accessibility is the practice of guaranteeing that interfaces are designed and developed to be usable by people with disabilities. It is often referred to as a11y due to having eleven letters between the first one (a) and the last one (y).

The first mistake I see people make is to associate the word "disabilities" with permanent disabilities. The truth is, disabilities can be situational, temporary or permanent meaning that we all can experience them on a daily basis.

These are some examples of each type of disability if we consider all the senses that a person can use on a UI:

Situations as commonplace as being in a subway can be considered a situational hearing disability. Considering the previous image, if your app or website requires the user to hear properly, you are not only excluding deaf people, but people with an ear infection, people who works on a noisy environment, and people using public transportation.

The web is accessible by default

As front-end engineers, we choose to break it or not all the time.

All the native HTML elements are built with a purpose, and they accomplish that purpose in the best possible way. As developers, we often build interactions using JavaScript as our first option, making everything work as we need. That way we might be rewriting features that HTML already provides, bypassing the built-in accessibility they have.

The best way to avoid this is to use the right HTML elements for the right purpose and then enhance them. This applies not only to basic elements but also to more complex components. Some native HTML controls that can be used with little or no tweaking are:

If what you're implementing works as a button, make it a <button>. If it works as a link, make it an <a>. You can change the way it looks using CSS. That's what CSS is for. Avoid creating functionality from scratch using <span> or <div> when there are native elements for it. This should be the obvious approach, especially to more seasoned developers.


WAI-ARIA is a set of attributes that add semantics to HTML to let browsers and assistive technologies know what is happening in the UI. It helps to communicate advanced interactions and dynamic content.

Example 1: Button that opens a dialog window

A simple example can be this markup of a button that opens a dialog window using JavaScript. As a human developer, you understand that this button shows/hides the section element, but the browser can't deduce that right away.

<button id="modal-trigger">Open modal window</button>

<section id="modal-content">Content inside modal window</section>

To help the browser understand this better, you can add some attributes. For example:

This is how it would look like:

<button aria-haspopup="true" aria-controls="modal-content" id="modal-trigger">Open modal window</button>

<section role="dialog" aria-hidden="true" id="modal-content">Content inside modal window</section>

Example 2: Button that closes a dialog window

Use WAI-ARIA only when necessary. Using the right markup is often enough. This is a counter-example of a button that closes a dialog window:

<div role="button" tabindex="0">X</div>

I've seen similar code in production uncountable times. These are some ways to take advantage of the native HTML elements:

Here is the exact same example but using cleaner, accessible code:


WAI-ARIA is like talking with the browser and assistive technologies to give them more information about dynamic interactions and content.

Find more info about it on the MDN documentation.


There is an Accessibility Object Model (AOM) in the browser that is built from the DOM tree and updated whenever the DOM is updated.

Here's the unofficial draft.

Adding the attribute aria-hidden removes the element and its children from the accessibility tree. What also makes the job is using the hidden attribute, display: none, or visibility: hidden. In those cases, aria-hidden is redundant and not necessary.

User's choice

Making a website accessible is basically giving the users the choice over how they consume your content.

For example, for animations on the UI, you can start with a static element and add an animation only when users have no preference for reduced motion:

.logo {
  color: black;

@media (prefers-reduced-motion: no-preference) {
  .logo {
    animation: alternate-colors 1s linear infinite;

@keyframes alternate-colors {
  0% { color: red; }
  50% { color: green; }
  100% { color: blue; }


Some tools I use to check a11y include, but are not limited to: