Accessible interactions

Accessibility on the web is easy. Accessibility on the web is also hard.

I think it’s one of those 80/20 situations. The most common accessibility problems turn out to be very low-hanging fruit. Take, for example, Holly Tuke’s list of the 5 most annoying website features she faces as a blind person every single day:

  • Unlabelled links and buttons
  • No image descriptions
  • Poor use of headings
  • Inaccessible web forms
  • Auto-playing audio and video

None of those problems are hard to fix. That’s what I mean when I say that accessibility on the web is easy. As long as you’re providing a logical page structure with sensible headings, associating form fields with labels, and providing alt text for images, you’re at least 80% of the way there (you’re also doing way better than the majority of websites, sadly).

Ah, but that last 20% or so—that’s where things get tricky. Instead of easy-to-follow rules (“Always provide alt text”, “Always label form fields”, “Use sensible heading levels”), you enter an area of uncertainty and doubt where there are no clear answers. Different combinations of screen readers, browsers, and operating systems might yield very different results.

This is the domain of interaction design. Here be dragons. ARIA can help you …but if you overuse its power, it may cause more harm than good.

When I start to feel overwhelmed by this, I find it’s helpful to take a step back. Instead of trying to imagine all the possible permutations of screen readers and browsers, I start with a more straightforward use case: keyboard users. Keyboard users are (usually) a subset of screen reader users.

The pattern that comes up the most is to do with toggling content. I suppose you could categorise this as progressive disclosure, but I’m talking about quite a wide range of patterns:

  • accordions,
  • menus (including mega menu monstrosities),
  • modal dialogs,
  • tabs.

In each case, there’s some kind of “trigger” that toggles the appearance of a “target”—some chunk of content.

The first question I ask myself is whether the trigger should be a button or a link (at the very least you can narrow it down to that shortlist—you can discount divs, spans, and most other elements immediately; use a trigger that’s focusable and interactive by default).

As is so often the case, the answer is “it depends”, but generally you can’t go wrong with a button. It’s an element designed for general-purpose interactivity. It carries the expectation that when it’s activated, something somewhere happens. That’s certainly true in all the examples I’ve listed above.

That said, I think that links can also make sense in certain situations. It’s related to the second question I ask myself: should the target automatically receive focus?

Again, the answer is “it depends”, but here’s the litmus test I give myself: how far away from each other are the trigger and the target?

If the target content is right after the trigger in the DOM, then a button is almost certainly the right element to use for the trigger. And you probably don’t need to automatically focus the target when the trigger is activated: the content already flows nicely.

<button>Trigger Text</button>
<div id="target">
<p>Target content.</p>

But if the target is far away from the trigger in the DOM, I often find myself using a good old-fashioned hyperlink with a fragment identifier.

<a href="#target">Trigger Text</a>
<div id="target">
<p>Target content.</p>

Let’s say I’ve got a “log in” link in the main navigation. But it doesn’t go to a separate page. The design shows it popping open a modal window. In this case, the markup for the log-in form might be right at the bottom of the page. This is when I think there’s a reasonable argument for using a link. If, for any reason, the JavaScript fails, the link still works. But if the JavaScript executes, then I can hijack that link and show the form in a modal window. I’ll almost certainly want to automatically focus the form when it appears.

The expectation with links (as opposed to buttons) is that you will be taken somewhere. Let’s face it, modal dialogs are like fake web pages so following through on that expectation makes sense in this context.

So I can answer my first two questions:

  • “Should the trigger be a link or button?” and
  • “Should the target be automatically focused?”

…by answering a different question:

  • “How far away from each other are the trigger and the target?”

It’s not a hard and fast rule, but it helps me out when I’m unsure.

At this point I can write some JavaScript to make sure that both keyboard and mouse users can interact with the interactive component. There’ll certainly be an addEventListener(), some tabindex action, and maybe a focus() method.

Now I can start to think about making sure screen reader users aren’t getting left out. At the very least, I can toggle an aria-expanded attribute on the trigger that corresponds to whether the target is being shown or not. I can also toggle an aria-hidden attribute on the target.

When the target isn’t being shown:

  • the trigger has aria-expanded="false",
  • the target has aria-hidden="true".

When the target is shown:

  • the trigger has aria-expanded="true",
  • the target has aria-hidden="false".

There’s also an aria-controls attribute that allows me to explicitly associate the trigger and the target:

<button aria-controls="target">Trigger Text</button>
<div id="target">
<p>Target content.</p>

But don’t assume that’s going to help you. As Heydon put it, aria-controls is poop. Still, Léonie points out that you can still go ahead and use it. Personally, I find it a useful “hook” to use in my JavaScript so I know which target is controlled by which trigger.

Here’s some example code I wrote a while back. And here are some old Codepens I made that use this pattern: one with a button and one with a link. See the difference? In the example with a link, the target automatically receives focus. But in this situation, I’d choose the example with a button because the trigger and target are close to each other in the DOM.

At this point, I’ve probably reached the limits of what can be abstracted into a single trigger/target pattern. Depending on the specific component, there might be much more work to do. If it’s a modal dialog, for example, you’ve got to figure out where to put the focus, how to trap the focus, and figure out where the focus should return to when the modal dialog is closed.

I’ve mostly been talking about websites that have some interactive components. If you’re building a single page app, then pretty much every single interaction needs to be made accessible. Good luck with that. (Pro tip: consider not building a single page app—let the browser do what it has been designed to do.)

Anyway, I hope this little stroll through my thought process is useful. If nothing else, it shows how I attempt to cope with an accessibility landscape that looks daunting and ever-changing. Remember though, the fact that you’re even considering this stuff means you care more than most web developers. And you are not alone. There are smart people out there sharing what they learn. The A11y Project is a great hub for finding resources.

And when it comes to interactive patterns like the trigger/target examples I’ve been talking about, there’s one more question I ask myself: what would Heydon do?

Have you published a response to this? :


Andy Bell

P much nodding along with all of that: it depends being the key for sure. I’m still a fan of a button for a modal if I can, but “extending” a link isn’t the worst thing if needs be. I’m the same as you: bother Heydon with it

# Posted by Andy Bell on Tuesday, October 27th, 2020 at 4:02pm

Jeremy Keith

I like the fallback you get with a link (assuming it’s using a valid fragment identifier)—if anything goes screwy with the JavaScript, the link still works.

Andy Bell

What I’ve started doing with stuff like accordions is rendering a headed group of content and passing that into something like a vue component or web component that then sucks all the content out and turns it into the interactive stuff. A thing called progressive enhancement?

# Posted by Andy Bell on Tuesday, October 27th, 2020 at 4:07pm

Evan Minto

I did exactly this recently on a project! Used hash links to control a modal and then enhanced with a WC. Button would be better tbh but to do that and keep the fallback you’d need to use role or have the WC swap out the link for a button (yuck).

# Posted by Evan Minto on Tuesday, October 27th, 2020 at 9:01pm

Marcus Herrmann

I totally missed that gem from @adactio. The truth is: modern web dev (and web app) accessibility follows the pareto pricinple (80/20). 80% is to harvest low hanging fruits. And Jeremy has strategies for that challenging 20% left

Adrian Roselli

I disagree with the advice on dialogs. URL does not change; no Back button; Esc or click/tap outside should not be same as pressing Back; dialog not in history object; right-clicking does not (should not) offer open in new window, add to bookmarks, etc…

Geoffrey Crofte 🔥

Adactio: Journal—Accessible interactions “As long as you’re providing a logical page structure with sensible headings, associating form fields with labels, and providing alt text for images, you’re at least 80% of the way there.”

José Leiva

Jeremy Keith describe un poco su proceso mental para tomar decisiones cuado esta trabajando con elementos que sigan un patron de progressive disclosure, como tabs, menus, modal, dialog, etc.

  • 80% del trabajo es “sencillo”, el 20% es cuando se vuelve tricky, porque entramos en áreas donde no hay reglas claras para tomar decisiones.
  • ARIA nos puede ayudar, pero no debemos abusar, causaria más daño que beneficio.
  • Se enfoca primero en cubrir que keyboard y mouse users puedan interacturar con el componente
  • Agregar algunos atributos extras, como aria-expanded, aria-hidden y aria-controls, para asegurarse que screen reader users no se estan quedando excluidos.

Par de preguntas que se hace cuando esta tomando decisiones:

  1. ¿Debe usar un boton ó un link en el elemento trigger?
  2. ¿Debe el elemento target recibir focus de manera automatica?

Ademas, después de haber leído un par de libros de Heydon Pickering, puedo hacer un +1 a su tercera pregunta.

And when it comes to interactive patterns like the trigger/target examples I’ve been talking about, there’s one more question I ask myself: what would Heydon do?

# Posted by José Leiva on Sunday, November 1st, 2020 at 12:00am


# Liked by George Salib® on Wednesday, October 21st, 2020 at 4:55pm

# Liked by Marty McGuire on Wednesday, October 21st, 2020 at 7:52pm

# Liked by Jan Boddez on Wednesday, October 21st, 2020 at 8:18pm

# Liked by Kim Krause Berg for Hire on Monday, October 26th, 2020 at 3:40pm

# Liked by Andy Bell on Tuesday, October 27th, 2020 at 4:14pm

# Liked by Stephen Mizell on Tuesday, October 27th, 2020 at 4:15pm

# Liked by 청설모 🎗 on Tuesday, October 27th, 2020 at 5:08pm

# Liked by Megan on Tuesday, October 27th, 2020 at 8:09pm

Previously on this day

1 year ago I wrote Indy web

Maps—they don’t love you like I love you.

6 years ago I wrote Indie web building blocks

Small pieces, loosely stacked.

7 years ago I wrote Classy values

Semantics and such.

8 years ago I wrote Visionaries

A memory of Austin prompted by a readlist of seminal technology papers.

9 years ago I wrote Candygram

A child’s Halloween in Ireland.

12 years ago I wrote Typorn

Geeking out on the printing press.

13 years ago I wrote Closed open data

When is an hCard not an hCard?

18 years ago I wrote Stop the Patent Process Madness

Wired has published an excellent article by Lauren Weinstein on the ludicrous state of Intellectual Property patents:

18 years ago I wrote The Morning News - The Opposite of Sex and the City

What if Sex and the City had been written by Beckett?…

18 years ago I wrote Guess the Dictator or Sit-Com Character

This is a scarily accurate online version of twenty questions. It didn’t take long for it to guess that I was thinking of Alex P. Keaton from Family Ties.

19 years ago I wrote Multiculturalism vs. feminism

The situation in Afghanistan has highlighted something of a dilemma for the liberal left - a group I would usually consider myself a part of.