Skip to content

Development Checklists

Image of the spider-man with triggered spider-sense

There are a number of tools we can use to assist in the creation of accessible web applications.

Here are some common issues that should make your spidey senses go off. My goal is for you to be able to identify these in code reviews and demos.

We want to bring kindness to these situations and not judge people. We also need to identify accessibility issues (ideally) before they ship:

Keyboard Navigation

By far the easiest and also one of the most important checks is to test if your entire website can be reached and used with the keyboard alone. Do this by:

  1. Disconnecting your mouse.
  2. Using Tab and Shift+Tab to browse.
  3. Using Enter to activate elements.
  4. Where required, using your keyboard arrow keys to interact with some elements, such as menus and dropdowns.

INFO

Note that not everything has to be interactive for screen readers (e.g. headings)!

Increase text size to 200%!

Is the content still readable? Does increasing the text size cause content to overlap?

Straw Testing

Proximity issues can arise when interface elements are designed far apart from one another. This mostly affects people with low-vision who rely on zoom software.

What happens when someone uses zoom software is that they only see a small fraction of the screen at once. Usually, the zoomed portion of the screen follows the current position of the mouse pointer or keyboard cursor.

As a result of someone only being able to see a small section at a time, oftentimes when attempting to complete a task, content is difficult to find or may be missed entirely.

How do we test to ensure there are minimal to no proximity issues with our design? One relatively simple and effective method is to perform what's called, "the straw test."

Modals

Modals are a big one. Anything that opens as a layer on top of other content has accessibility requirements, including:

  • Sending focus into the new content when it opens.
  • Restoring focus to the element the user was on previously when closing the layer.
  • Preventing keyboard and screen reader interaction with elements in the background.
  • Using a dialog role, focusable and labeled buttons and CTAs.

Non-modal dialogs don’t have all of the same background requirements. But the goal is still to move focus into relevant content when a non-modal dialog opens and closes.

Don't be a div button creator!

It’s real easy to add a click event to a div. Too easy, in fact. And it happens all the time! the problem is, divs are not interactive elements so you have to backfill quite a few things to make them accessible. All the while, you could have just used a <button> element and been done with it.

What if we really need to be a div button creator?!

First, do the easiest part!

tsx
const MyComponent = () => {
  const fn = () => {
    console.log("clicked on the div!")
  }

  return (
    <div 
      onClick={fn} 
    >
      click!
    </div>
  )
}

Then we set a role="button" attribute. based on MDN documentation:

The button role is for clickable elements that trigger a response when activated by the user. Adding role="button" tells the screen reader the element is a button, but provides no button functionality.

tsx
const MyComponent = () => {
  const fn = () => {
    console.log("clicked on the div!")
  }

  return (
    <div 
      role="button"
      onClick={fn}
    >
      click!
    </div>
  )
}

Now we need should pass key down event handler for keyboard interaction:

tsx
const MyComponent = () => {
  const fn = () => {
    console.log("clicked on the div!")
  }

  const handleKeyDown = (e: KeyboardEvent) => { 
    if (e.code === 'Space' || e.code === 'Enter') { 
      fn(); 
    } 
  } 

  return (
    <div 
      role="button"
      onClick={fn}
      onKeyDown={handleKeyDown} 
    >
      click!
    </div>
  )
}

We are not done yet! The element can trigger the fn function using Enter and Space keys, but the problem is the element is not focusable and we should bass a tabIndex attribute to the div element.

tsx
const MyComponent = () => {
  const fn = () => {
    console.log("clicked on the div!")
  }

  const handleKeyDown = (e: KeyboardEvent) => {
    if (event.code === 'Space' || event.code === 'Enter') {
      fn();
    }
  }

  return (
    <div 
      role="button"
      onClick={fn}
      onKeyDown={handleKeyDown}
      tabIndex="0"
    >
      click!
    </div>
  )
}

QUESTION: Wasn't it eassier to use the following approach instead?

tsx
const MyComponent = () => {
  const fn = () => {
    console.log("clicked on the div!")
  }

  return <button onClick={fn}>click!</div>
}

That’s it. No explicit button role, no tabIndex, no key handler (because buttons will fire from clicks with the keyboard, unlike divs)

Use prefer-reduce-motion for your animations!

Warning

An embedded example in this section has a scaling movement that may be problematic for some readers. Readers with vestibular motion disorders may wish to enable the reduce motion feature on their device before viewing the animation.

The prefers-reduced-motion CSS media feature is used to detect if a user has enabled a setting on their device to minimize the amount of non-essential motion. The setting is used to convey to the browser on the device that the user prefers an interface that removes, reduces, or replaces motion-based animations.

Such animations can trigger discomfort for those with vestibular motion disorders. Animations such as scaling or panning large objects can be vestibular motion triggers.

Accessible Media

Make note of any media in need of captions, transcripts, and other alternative content.