But Why??

A presentation at EmberFest in September 2024 in Dublin, Ireland by Melanie Sumner

Slide 1

Slide 1

But…why??

A look at common patterns found on the web, how they are harmful for accessibility, and what to do instead.

Slide 2

Slide 2

Intro to Melanie

  • Product Accessibility Lead, HashiCorp
  • Invited Expert, WAI-ARIA & AccName, W3C
  • Core Team, Ember.js
  • @a11yMel@front-end.social

Slide 3

Slide 3

So, why this talk?

Anyway, I want to take a minute and talk about why this talk.

I’m the product accessibility lead at HashiCorp, and I work on the Design Systems Team. You may have heard of our design system, Helios. I love it. It uses semantic markup, it has lovely design, it meets accessibility compliance requirements, we have tests and really thorough documentation.

It’s been a dream to work on.

Slide 4

Slide 4

accessible design system != accessible application

But as y’all know, I’ve been talking with our community for a long time about accessibility, and that a design system alone does not make your application accessible.

But what really solidified this talk as more than just a saying or concept, was that while working to make our design system components REALLY accessible… And really tested… And really documented….

I noticed that I kept seeing similar accessibility issues in the applications using our design system, so… I started taking some notes.

And then those notes started taking more shape. And then Marco said, “please talk at EmberFest” So I said yes, because I knew what I wanted to talk about. Plus Dublin, so obviously.

Slide 5

Slide 5

Agenda

And that brings us to my most predictable slide, the agenda.

  1. First, we’ll look at some UI examples
  2. Then we’ll look at where each example fails for accessibility
  3. Then we’ll look at what to do instead.
  4. PS we may have some detours
  5. P.P.S. I’ve practiced this a lot and will try very hard to keep to 30 minutes.

Slide 6

Slide 6

Some Disclaimers

But first, some disclaimers.

The premise of this talk is that we’ll look at patterns in real life and that means real code. I don’t show you these things to shame any designer or developer, because we’ve all written code and later looked back and thought “oh dear lord what have I done” I did that just this morning even.

I show real patterns and real code I want to guide us to do better, which means looking at real stuff. That way we can do better, next time.

I’ve said it before and I will say it again, accessibility is a journey. It’s about progress, not perfection.

Slide 7

Slide 7

Accessible Names

First up: how do you make unique, accessible names?

Slide 8

Slide 8

Example UI: Adding integrations

In this UI example, we see something that is very common in technical apps today: the ability to add integrations with different products, or maybe login with different platforms.

We see these cards, each with the company’s logo, the name of the company that could be potentially integrated with, and the link that will take you to the page where the user can perform that action.

Slide 9

Slide 9

Where this breaks for accessibility

Where this breaks for accessibility is that all of these links have the same name, even though they go to different URLs.

Now, real quick: The mechanism for screen readers that allows users to navigate through a site by groups of elements is called different things in different screen readers. I’m going to call it a rotor, because in VoiceOver on Macs, that’s what it’s called. Just know that it is probably called different things by different screen readers.

In this case, if the user is navigating by rotor, they will see a list of links, all named “add”. Add…what? There’s no way to differentiate these links from each other in the same quick way that a sighted user can.

Slide 10

Slide 10

Each link needs a unique accessible name

Even if the user navigates with the just the TAB key or the keyboard shortcut to go to the next link, going from one interactive element to the next, they will still hear “Add, link” over and over and over again.

That’s…not useful.

Slide 11

Slide 11

What might this code look like?

So before we look at some options, let’s take a quick look at what this code might look like. This code sample is heavily edited so we can focus on the important bits.

  • We see the icon there, correctly hidden with aria-hidden=”true”.
  • We see the name of the potential integration.
  • We see the link to add that integration.
  • We can even imagine the styling that went into it to make the little card that renders to the browser.

Slide 12

Slide 12

Equally viable options to consider

The aria-label attribute

  • Takes a string value
  • Good option for when there is no existing element to reference
  • Sometimes a bit quicker to implement
  • Not additive; will replace content with its value.

The aria-labelledby attribute

  • Takes an elementʼs id as its value
  • Can have multiple values (space separated)
  • Will ignore repeated values
  • Can reference…itself.
  • Will replace text content with its calculated total value

Slide 13

Slide 13

What to do instead: the aria-label option

Let’s look at the option using the aria-label attribute.

In this approach, we add the aria-label attribute to the link, concatenating the word “Add” along with the Integration name. When rendered, we’ll still have the same element(s) in the browser.

And like the aria-labelledby option, the screen reader will tell us “Add GitHub Actions, Link”

Slide 14

Slide 14

What to do instead: the aria-labelledby option

So let’s see what it looks like to use the aria-labelledby attribute to fix this problem.

We’ll start by adding an id attribute to the div with the integration name Then we’ll add an id to the span with the word “Add” in it. Then on the link, we’ll add the aria-labelledby attribute with the two id attributes we want to use, in the order we want them to be read to the user. When rendered, we’ll still have the same element(s) in the browser.

And we’ll get the same result, the screen reader will tell us “Add GitHub Actions, Link”

Slide 15

Slide 15

Users can navigate by element groups

So if we compare the rotor list we saw before With a rotor that has a list of links with accessible names We can immediately see where the improvement is. The user can now differentiate quickly and easily. Which one would you prefer?

Slide 16

Slide 16

Bonus Example: Accordion using aria-labelledby

Here’s a little bonus example, an accordion item using the aria-labelledby attribute. By adding an id attribute to the h2 element that gives the accordion item a heading, (click) we can then use that id attribute value for the aria-labelledby attribute on the button element.

Furthermore, because we have the aria-expanded attribute here, the user will be informed if the element is expanded or collapsed. So we get that information for free.

Slide 17

Slide 17

DETOUR

Ok. I did warn you there might be a detour, and guess what, it’s time for a detour.

Slide 18

Slide 18

The Accessible Name and Description Computation

A detour into the accessible name and description computation specification. Wow that’s a mouthful. I just call it AccName. You can too if you want. It’s easier and people will know what you mean.

This detour is happening because I’ve had too many developers tell me that they don’t understand AccName and I’m the co-editor. So I feel responsible for that.

So I’m going to take a few minutes and explain a few things because it’s worth it to understand what’s going on here.

Slide 19

Slide 19

Detour Agenda

So I’m going to explain this to y’all from a few angles. That’s why we have a mindful detour agenda. First, some context Then we’ll look at the accname instructions for the browser Then we’ll talk about some ways browsers are like, ”yeah but no” Then we’ll look at the guidance for developers Then the accessible description instructions for the browsers And finally the developer guidance for descriptions.

Slide 20

Slide 20

3 things to know about this spec

So. Three things to know about this spec.

First, it provides instructions to browsers for how to calculate the accessible name and the accessible description. Both may exist. Neither may exist. Browsers need to figure that out,

Because the browser’s goal is to return the results to the accessibility object.

Now, they will follow the specification FOR THE MOST PART. But, they may also do other things if they are convinced they need to do that.

Slide 21

Slide 21

AccName: Browser Instructions

Browsers are supposed to return the first thing they find, looking in this order: Look for an aria-labelledby attribute Then look for an aria-label attribute with a non-empty value Then look for an aria-describedby attribute Look for semantic content (text of a button element. Label. Legend.) Finally, if there’s nothing else, look for title or placeholder attribute.

Slide 22

Slide 22

AccName: Browser Exceptions

There are some edge case exceptions to know about, so you don’t run into them and then are like “WTF MEL YOU TOLD ME THE WRONG THING”

First, we previously noted that they must return the first thing they find…even if that thing has an “empty” string. And this really makes like, a space between your quotes. Not even joking. It’s because there’s been a lot of back-and-forth to explicitly define how whitespace should be handled in the AccName spec, and browser implementers kind of have to agree. So there are some realllllllly weird edges to this one. Just make sure that you’re not putting any whitespace in your “empty” strings.

Second, they can choose to expose text even if you’ve used the aria-hidden attribute on it. This is because they feel it’s better to return something to the user with AT, rather than nothing. So “thar be dragons.”

Finally, browsers implement exceptions as they see fit. There is no specification for implementing exceptions. So…just…idk.

The thing is, if you aren’t doing weird stuff then you’ll probably be fine. It’s when developers try to get clever that these issues crop up.

Slide 23

Slide 23

AccName: Developer Guidance

Semantic content should be your default go-to. The first rule of aria is to not use aria if you can help it. It really is the best and the most reliable thing to do. If a suitable element that can be used to provide the label content: use the aria-labelledby If no suitable label already otherwise exists: use the aria-label attribute Don’t use the placeholder or title attributes for an accessible name. They just weren’t implemented appropriately and are terrible. So just don’t do it. Placeholders, if used at all, should be used to demonstrate to the user the formatting for the data you’re asking them for. That’s it. Maybe. You’ll read online that aria-label is not translated. This is referring to sites that rely on google translate in the browser to translate the page. But you’re Ember developers and you use i18n and all, yeah? So you don’t have to worry about it.

Slide 24

Slide 24

AccDesc: Browser Instructions

AccDesc: browser instructions Look for an aria-describedby attribute (if not used for AccName) Then look for an aria-description attribute Then look for elements that are eligible for the description calculation, and not already used for the accessible name computation: table caption text content summary element, text equivalent computation of subtree The title attribute value (again, if not already used)

Slide 25

Slide 25

AccDesc: Developer Guidance

AccDesc: dev guidance Semantic content (i.e., Table caption element content) Use the aria-describedby attribute for help and error text Takes an id as the value It can have multiple values (space separated id attributes) The aria-description attribute is also a possibility It should have a string value It is preferred to put descriptive text in the DOM, though.

Loosely, you can think of aria-describedby as the description equivalent of aria-labelledby And aria-description as the description equivalent of aria-label

Slide 26

Slide 26

End Detour

And that is the end of this detour. If you have specific questions or want to know more about things like why it’s so hard to define whitespace rules in the accname spec, come talk to me later.

Slide 27

Slide 27

Headings, Labels, and Instructions

Ok, on to the next. Let’s look at Headings, Labels, and Instructions. I grouped it this way because there is WCAG guidance about Headings and labels And also Labels and instructions And in my experience, all of these things end up being related to each other. So here we are.

Slide 28

Slide 28

Headings

First up, let’s talk headings.

Slide 29

Slide 29

Headings TL;DR

Here’s your headings cheat sheet HTML heading elements for semantic meaning, CSS for styling Every section should have a heading Headings need to be in order

Browsers will change, and over time, expand to support MORE things But these rules will always apply no matter what

Slide 30

Slide 30

If it looks like a heading, and acts like a heading…

Let’s look at an example.

If you have, let’s say, a modal And you give that modal a title And that modal’s title looks like a heading…

Slide 31

Slide 31

…but doesnʼt sound like a heading… 31

But, that modal title that looks like heading but doesn’t sound like a heading to a user with a screen reader

Slide 32

Slide 32

…then itʼs not a heading, itʼs an #a11yFail

Then it’s not a heading, it’s an accessibility failure.

Slide 33

Slide 33

Why headings matter

This matters because the heading tells the user what that part of the page is about.

This matters because users with screen readers can navigate to the next heading with a keypress.

This matters because users with screen readers can navigate through a list of all headings

This matters because it provides users with the means to quickly navigate to the part of the page they care about. Or get an overall idea of what the different sections of the page are.

Like you can do. All at once. With your eyes.

Slide 34

Slide 34

Headings: What to do instead

So, what to do instead?

Turn it into a header if it’s acting like a header. Let’s think about that modal. A modal, when implemented correctly, will use the dialog element and mark the rest of the page as inert, or unusable.

Now, If we think about this from the perspective of the user with AT Either the page “exists” or the modal “Exists” But both do not exist at the same time.

If we pair this concept with the “have a single h1 per page” concept Then we can see that modals should have an h1 as their title heading element.

Slide 35

Slide 35

Labels

Next up: labels.

Slide 36

Slide 36

Label requirements

Here’s your label cheat sheet.

Labels must exist The markup must be valid and the label must be correctly associated with the input The label must also be informative and the user must be able to discern what is required of them for that input. Finally, the visible name of the label must also be in the accessible name of the label. This is for users who use speech control software.

That’s FIVE different ways labels could fail for accessibility. FIVE. For ONE THING. This is why I frequently tell folks to not get all bendy with the code they put on the web.

Slide 37

Slide 37

Label Example #1

So let’s look at a couple of label examples and see what’s what. First up, we have a lovely application name label here. Let’s peek at the rendered code. (click) Ok, let’s apply the cheat sheet: Exist, Correct, Clear, Visible.

  • Exist: Does a label exist? (click) Yes.
  • Correct: Is is associated correctly with the input? (click) well, we’re missing the for attribute on the label and the id attribute on the input, so we’ll say no here.
  • Clear: Is it informative enough for the user? Yes
  • Visible: Is the visible label in the accessible name? Since the accessible name here is non-existent, the visible label is not in the accessible name, so No .

Slide 38

Slide 38

Label Example #2

Let’s look at this other example. Here we have an input with the label of “Name” Let’s peek at the rendered code. (click) Again, let’s apply the cheat sheet: Exist: Does a label exist? (click). Yes Correct: Is is associated correctly with the input? (click) yes, we see the label/for and input/id Clear: Is it informative enough for the user? Hmm. Name. First name? Last name? Full name? What does name mean here? (click) This would fail, because it’s not informative enough. Visible: Is the visible label in the accessible name? (click) Yes, the visible label is in the accessible name, so it would pass that criterion.

Slide 39

Slide 39

Label Example #3

One more example. Here we have an input asking for your cat’s name Peeking at the code (click) We see…oh! We see an aria-label here. Perhaps the developer wanted to give the screen reader user extra information. Perhaps they were trying to be helpful. When we turn on Voiceover (click) we see that the accessible name of the input is “what do you call your cat?” So let’s see how this stacks up in our little checklist.

Exists: (click) yup, the label exists for the input field Correct? (click) yup, the label is correctly associated with the input Clear? (click) yes, the label is clear…in both cases. Visible (label in accname)? (click) now here’s where it fails. The visible label is not in the accessible name.

Slide 40

Slide 40

Labels: What to do instead

So fixing our labels, let’s look at a corrected example of the Application Name labeled input.

(click) we’ve added the for attribute to the label element and the id attribute to the input element.

How does it stack up?

Exists? (click) yuppers! Correct (click) definitely now correctly associated! Clear? (click) well that passed before, so it isn’t going to fail now. The label is clear enough. Visible name in accName? (click) you betcha!

Slide 41

Slide 41

Bonus: helpful cat lady

And I’ll tell you this for free, you can still give a little extra hint to users with screen readers.

In the cat’s name example, it was incorrect because the visible label wasn’t in the accessible name.

However, if we change aria-label to aria-description, we get (click through) Green lights all the way!

Don’t do this for all help text, but you can do it if you want to add a little something extra for screen reader users.

Slide 42

Slide 42

Instructions

Ok now to the third part of this. Instructions.

Slide 43

Slide 43

Instructions example: delete confirmation modal

Let’s think about instructions in terms of help text. Now let’s look at this modal. How many accessibility issues do you see just by looking at it? (pause) There are at least four that are visible from this screenshot. Since we already talked about headings, let’s look at the other three.

Slide 44

Slide 44

Whatʼs wrong with this picture?

First, we have the word “DELETE” in all uppercase - this is problematic because not all screen readers treat uppercase letters the way they are supposed to. On top of that, voice engines (the voices used in screen readers) have varying levels of support to read uppercase letters correctly.

Second, we have the word “below.” This is referred to as a sensory characteristic. Except, the user with a screen reader hears this when they are focused on the input field, so what does “below” mean? It only has meaning for the sighted user.

Third, we have a disabled button, which means that the user with a screen reader may not even know that the button is even there. In VoiceOver, it will say “button, dimmed” which is the hint to the user that a disabled button exists, but in general, if an interactive element has the disabled attribute, then it’s completely hidden from screenreaders.

Slide 45

Slide 45

A note about uppercase

So because we have delete in all uppercase And the delete button isn’t active until we get it right Only, the user may not hear that it’s in uppercase (a common setting is to announce the word in a higher pitch, like (say it in a higher pitch) DELETE) So the users types in delete in lowercase and still nothing happens. They are blocked from continuing and have no guidance here as to why.

Slide 46

Slide 46

What to do instead: improved instructions

So let’s say that our designer is super busy and we want to make this more accessible and not drastically change the design because we love our designers and we want to keep our happy relationship. What do we do?

We’re going to change the help text in two ways. First, we’re going to put parentheses in with the “all caps” so that a user with a screen reader will definitely know that uppercase DELETE is required. Next, we’re removing the word “below” because if you’re focused on the input when you get those instructions, there is no “below”…and if you can see the screen, there’s only one input there so in addition to a violation of the WCAG Success Criterion Sensory Characteristics Finally, we’re updating the button text to “Confirm Delete” and we’re not going to disable the button; The user will get an error message if they do not fill in the field properly, and that’s not only completely acceptable, it’s ideal. Our form’s validation can make sure that absolutely nothing happens to the user’s data unless they fill out the form correctly, and ALL users will be able to figure out what is expected from them.

Slide 47

Slide 47

Reflow, Resize, Space

Next section is reflow, resize, space

And by this I mean three WCAG requirements that are all related: Reflow Text resizing Text spacing

Slide 48

Slide 48

We don't support mobile, they say...

Now your designer might say, “we’re a desktop app. We don’t “support” mobile.”

and then they give you a bunch of designs with fixed pixel widths everywhere, which is Figma’s fault, but ya know what?

It’s only mostly Figma’s fault. There’s math for responsive design, and developers are more than capable of doing math. Or maths if you prefer. So I don’t really accept the excuse.

target ÷ context = result

It’s 2024 and you don’t “support” mobile? Ya sure about that?

But fine, time is money and money is constraints.

Slide 49

Slide 49

What weʼre trying to do... What are our desired outcomes for the user?

Let’s think about this in terms of desired outcomes, though.

What do we want the user to be able to do?

They should be able to zoom up to 400% They should be able to increase the font size up to double They should also be able to increase all facets of spacing for text.

Slide 50

Slide 50

Incorrect Reflow example (before zoom)

Ok so let’s look at an example of a reflow failure. Here we have a banner on a website, I’ve blurred the unimportant stuff here. This is at full width, where things are as they should be.

Slide 51

Slide 51

Incorrect Reflow example (after zoom)

But then once we zoom in, we see that the content has not reflowed…it’s starting to become clipped and unreadable. This was not even at full zoom. At full zoom, the content would not be visible. The container is no longer meeting the sizing needs of the content inside.

Slide 52

Slide 52

Correct Reflow example (before zoom)

When done correctly, none of the content is hidden or clipped when browser zoom is used.

Slide 53

Slide 53

Correct Reflow example (after zoom)

The content is still visible and fits the viewport, and it does not require the user to scroll in two directions to see content. Or not see the content at all because overflow was hidden.

This also mostly applies to text resizing as well; while users can especially only just resize their text, using browser zoom has become commonplace enough for that to be an acceptable check in most cases.

Slide 54

Slide 54

Text Spacing example (before)

For text spacing, let’s look at a before and after first.

Here is some website content before the text spacing requirement has been applied.

Slide 55

Slide 55

Text Spacing example (after)

And here it is after the text-spacing requirements have been applied.

So let’s look and see what those are.

Slide 56

Slide 56

Spacing text

  • Users should be able to change the line height
  • The spacing that follows a paragraph
  • Letter spacing
  • And word spacing

Since these all should support very specific amounts, have a CSS class you can use for testing, or a bookmarklet and try it out in the browser. https://www.w3.org/WAI/WCAG22/Understanding/text-spacing

Slide 57

Slide 57

What to do instead for reflow, text-resizing, and text-spacing

To successfully do this, you’ll want to use all of the lovely techniques we have for responsive design.

Relational units Unitless line heights. Grid and Flexbox CSS

And make sure you test!

TBH In the end, “browser zoom support” ends up looking a whole lot like “mobile viewport support”

Slide 58

Slide 58

Takeaway

The takeaway here is that if you meet the accessibility success criteria for reflow, text resizing and text spacing, you sorta get some responsive design for free.

Slide 59

Slide 59

Putting it all together

Okay, let’s put all of these things together and wrap this up.

Slide 60

Slide 60

WCAG is the bare minimum

The WCAG success criteria are the bare minimum of requirements for people with disabilities to use the internet. There is so much more beyond that to make sure we’re providing an equivalent experience.

Slide 61

Slide 61

What are we really trying to do here?

I want you to think beyond. What are we really trying to do here? Think about what a delightful user experience is for all types of users. Think about how you could do more. Maybe the next level for you is internal requirements.

Slide 62

Slide 62

Internal Requirements

“How can we go beyond, Mel?” I’m delighted you asked. Here’s some ideas. Outline the bare minimum WCAG requirements internally, and then explain ways that your products will do more. Outline requirements for design. For code. For how you will test. For how you will integrate accessibility reviews into your product development and release process.

Slide 63

Slide 63

Be a little selfish

The thing is, I am calling on all developers to be a little more selfish. Did you know that there’s such thing has an “age burst” and the first one happens (or will happen) to you in your mid 40’s?

Play a video game one day? Have tennis elbow for a month. Hear a sudden noise and turn your head too quickly? You just have a sore neck that’s your life now. Then one day you need reading glasses. Then six months later, you need stronger reading glasses. And your doctor says that your eyes will settle down but you don’t know if you believe that because a year ago you had 20/20 vision. Everything just kinda…hurts now.

Slide 64

Slide 64

As front-end developers…

So be a little selfish.

Try out your front-end with your keyboard. Check the color contrast with an automated tool that does the math for you. Use browser zoom and make sure it works, and give your eyes a break.

You’ll improve your apps a little bit for accessibility…and your future self.

You might be saying, Mel I won’t be around to use these apps in the future, I’m sure they’ll be re-written by then anyway.

But every single developer influences the way that code for the web will be written in the future. What are you teaching those who come after you?

Slide 65

Slide 65

In Closing...

Finally, I’ll just say this.

You do not require permission to create accessible code. It doesn’t have to be explicitly stated in the requirements, you don’t have to be specifically told to do it. You don’t require permission. Create accessible code.

As the Irish say, cop on.