How Product Teams Can Work Together to Build an Accessible User Experience: Creating Scannable Web Pages for Assistive Technology

This Coforma blog series provides product teams with hands-on guidance for implementing workflows and best practices that prioritize the creation of an accessible user experience.

Jared Cunha
Coforma
15 min readMay 20, 2021

--

An image demonstrating how a screen reader dialog box would appear to show headings of an article, which says Design Focus: Accessible User Experience.

Over the course of my career, I have bounced back and forth between being a designer and a front-end developer. Most of the time, when I would design something, I would write most of the front-end code needed to implement it. I liked doing it. It also gave me some assurance that the design would be implemented properly, and the code would be clean. I’d run the HTML through my validation tools. Then I’d run it through one of my accessibility tools. No Web Content Accessibility Guidelines (WCAG) errors. No Section 508 errors. That work was DONE. It was clean; it was accessible.

Well, not quite. At some point, I learned that automated tools will only catch about 20-30% of the accessibility issues on your page. Essentially, these tools will tell you whether or not your code contains bugs. The other 70% relates to user experience issues. Left unchecked, at best, users will encounter additional, unnecessary frustration; at worst, they will not be able to receive critical services. The only way to address that other 70% is through manual testing. When I started trying to use my designs either with a keyboard or a screen reader, it really blew my mind how much I had overlooked. The anxiety hit me like a freight train, because I knew I put a lot of work out there that wasn’t manually tested.

Because accessibility often occurs in that gray area that falls between design and development, it is really everyone’s job — product managers and product owners, too!

Developing a Workflow that Prioritizes Manual Testing for Accessibility

As we know, accessibility covers a lot of ground: cognitive abilities, motor-function abilities, hearing, as well as sight. In all engagement with digital products, users still seek a clear understanding of what they can do, whether it’s to engage with other people, complete a form, learn something new, or withdraw money from their account. The fact that they might not have fine motor skills or clear vision shouldn’t block them from participating in “The Thing.”

Concentrating on the visual aspect of accessibility, I want to dive deeply into approaches that product teams can take.

I also want to stress, as a sighted user with all the domain knowledge of our own work, manually testing that work with assistive technology in no way replaces testing with real users. What it can do is remove some common hang-ups and allow research to uncover deeper usability issues.

When projects get moving, responsibility for creating an accessible experience may vary depending on the makeup of the team and individual expertise, but it is critical that everyone be part of the accessibility conversation. One might assume that using devices with assistive technology would mean expensive software, but there’s a good chance that software is already included on your machine, and if not, is freely available.

If you use Apple Products, you can enable VoiceOver, their built-in screen reader, on your MacOS or iOS devices. It takes a few minutes to learn how to use the MacOS keyboard shortcuts or iOS gestures and get started. VoiceOver is built to work with Safari, so if testing websites, you’ll want to use that.

If you are using Windows, you can check out NVDA for free or try out JAWS.

Another piece of assistive technology every machine has installed is the tab key, which is used for keyboard navigation. You might need to enable full keyboard accessibility if you are on a Mac.

After development is complete, the team will check to make sure that their work has been implemented as specified in their deliverables. Design and development teams should be conducting accessibility tests with screen readers and keyboard navigation in parallel with their visual QA work. In time, this process will start to become muscle memory, and when each team member is familiar with using assistive technology, they can more effectively have the conversations that prioritize accessibility considerations upfront.

This series will attempt to help product teams think about the user experience with assistive technology by drawing parallels with some of the ways sighted users experience the web and how we use visual and interaction design to provide that experience. We’ll look at examples that might pass an automated accessibility test but fail to make an accessible user experience. Some high-level HTML samples are included as examples of small changes that improve the user experience. These examples, paired with screenshots of what screen readers or other assistive technology are actually doing, provide some insight into how users with certain disabilities experience the web. It can be a starting point for teams to work together, and to begin having conversations about a more inclusive approach to user experience.

Scanning the Page

Whether you’re looking at a page for the first time or the hundredth time, you’re performing a quick scan. As you begin to get familiar with your screen reader, close your eyes and try to accomplish a task. Think of one that might consist of several steps. Aside from the obvious difference — being able to see — you will notice that the screen reader will only read where you’ve moved your indicator… to a button, for instance.

When you open your eyes, you can see everything that exists on the page: a content structure, navigational elements, forms, tabular data, and how all of those elements on the page relate to each other and the page’s overall purpose.

A visually impaired user doesn’t need to read through every single piece of content on the page in order to get that same information. Screen readers include a special feature called a rotor menu, and that is what a visually impaired user would use as a way to scan the contents of a web page similarly to how a sighted user would. In addition, the rotor menu serves as a navigational tool for jumping to specific sections, specific links, or form controls.

Rotor menu enabled on Coforma.io
Rotor menu enabled on Coforma.io

The HTML on the page generates the content within a rotor menu. Well-written, semantic HTML can make the rotor menu incredibly helpful. Poorly written, unsemantic HTML can make the rotor menu confusing or detrimental to the user experience.

The rotor menu contains several key sections. To control the rotor menu, use the left and right arrow keys to move between sections, the up and down arrow keys to select a list item, and the enter key to go to that element.

Landmark Roles

Landmark roles are one of many ways to make what appears in the rotor menu more meaningful. ARIA Landmark Roles are sections of the webpage that serve exactly as the name implies: navigational landmarks. The landmark roles are defined below.

  • banner: Includes prime heading or internal page title. Indicated with role="banner or <header>.
  • complementary: Supports the main content but can be separate and meaningful on its own. Indicated withrole="complementary" or <aside>.
  • content info: Info about the parent document, usually containing links to privacy policy and copyright. Indicated with role="contentinfo" or <footer>.
  • form: Contains form-associated elements. Indicated with role="form" or <form>, but does not appear in the rotor.
  • main: Contains the main content of the document. Indicated with role="main" or <main>.
  • navigation: Contains navigational links within or related to the document. Indicated with role="main" or <nav>.
  • region: Content that is relevant to an author-specified purpose and important enough that users will want to navigate to specifically. Indicated using <section> with an accessible name provided by aria-labelledby, aria-label, or title .
  • search: Contains a search tool. Indicated by role="search".

Some of these landmarks might appear obvious where they begin and end, but developers should work with designers on exact designations. For example, it’s really important that the main content is really the main content because, in the rotor menu, these are both important definitions and navigational elements. Placing main content outside of the role="main" landmark might cause users to miss important content, while placing content that isn’t main content inside the role="main" landmark could degrade the user experience because the user would have read through irrelevant content.

It is also possible to have more than one landmark role on a given page. For example, multiple navigational landmarks are quite common. You can provide helpful context inside the rotor menu by using aria-label, aria-labelledby, or title (though this attribute provides a name, we don’t recommend using it to name landmarks). Using aria-labelledby is preferable because it references another HTML element, allowing the translation plugins to translate the content.

Without naming these navigation landmarks, they will display in the rotor menu as navigation and navigation. Even though there is a heading element inside the landmark, it will not sufficiently name the landmark.

<nav role="navigation">
<h3 class="screen-reader-only">Main</h3>
<ul>
<li><a href="#">Nav 1</a></li>
...
</ul>
</nav>
<nav role="navigation">
<h3 class="screen-reader-only">Social media</h3>
<ul>
<li><a href="#">Twitter</a></li>
...
</ul>
</nav>
Screen shot of rotor menu containing two unnamed navigation landmarks, one listed as “navigation” and the other listed as “navigation.”
Without providing accessible names to landmarks, it is impossible to tell the difference between the two navigation menus.

Naming these landmarks with aria-labelledby gives each of them a clear name in the rotor menu, displaying as “Main navigation” and “Social media navigation.” Note that you will not need to include the word “navigation” in the name itself. We have also changed the heading to a <span> because, in this case, the headings might not be useful in the rotor menu’s headings section as part of the document outline. Even though this example illustrates a name that is hidden from sighted users, there are often times where it should be made visible.

<nav role="navigation" aria-labelledby="main-heading">
<span class="screen-reader-only" id="main-heading">Main</span>
<ul>
<li><a href="#">Nav 1</a></li>
...
</ul>
</nav>
<nav role="navigation" aria-labelledby="social-heading">
<span class="screen-reader-only" id="social-heading">Social media</span>
<ul>
<li><a href="#">Twitter</a></li>
...
</ul>
</nav>
Screen shot of rotor menu containing two named navigation landmarks, one listed as “Main navigation” and the other listed as “Social media navigation.”
Naming the navigation menu with aria-labelledby, the main navigation and social media links are easy to find.

Best Practices for Product Teams

Improving the user experience with landmark roles can be achieved through the following best practices:

  • Ensure roles are properly defined and communicated.
  • When using aria-labelleby, the team should discuss whether the associated element should be a heading (if the heading also helps outline the document structure) and whether the element should be made visible to sighted users.
  • Give meaningful names to landmarks that are special sections, or where multiple landmarks exist.

Headings

The headings section in the rotor menu outlines the structure of the page content. Think about the way you look at a Word document or Google Pages outline. That is what this part of the rotor menu does. If your headings are not nested properly, your document structure will convey content incorrectly.

Note that the code here jumps directly from level 1 to level 3. For a sighted user, this is a detail that might not matter much because the visual hierarchy would be unaffected. However, in the rotor menu, it is difficult to determine what the true structure of the page might be.

<h1>Improper nesting order</h1>
...
<h3>Section of the page</h3>
...
<h4>Subsection of the page</h4>
...
Screen shot of rotor menu containing headings nested improperly, an H1 followed by an H3, followed by an H4. Behind the rotor is some copy where the visual design doesn’t convey the accessibility error.
Using HTML elements set heading font sizes fails to properly communicate the page structure to screen readers by jumping from level 1 to level 3.

Always use the semantic heading nested in the correct order. If you want to change any aspect of the heading’s presentation, use CSS. Here is the same document using utility classes to set the heading presentation. You don’t have to use utility classes, but you should always use CSS. Now, the rotor menu displays the proper document structure.

<h1>Proper nesting order</h1>
...
<h2 class="font-size-lg">Section of the page</h2>
...
<h3 class="font-size-md">Subsection of the page</h3>
...
Screenshot with a rotor menu containing headings nested properly, an H1, followed by an H2, followed by an H3. Behind the rotor menu shows example paragraph text without any visual design changes from the incorrect example.
In this example, we are using CSS to set the font size of the headings. The visual design has not changed from the previous example but the nesting order is now correct.

Best Practices for Product Teams

Improving the user experience with headings can be achieved through the following best practices:

  • Instead of talking about heading sizes by their heading level, “Use the H3 instead of the H2,” for instance, talk about them using some other label. “Use the large font size for H2s instead of the extra-large font size.” Talking about font sizes by heading level may lead developers to implement them that way.
  • Think about where some sections of content might help visually impaired users by placing a heading that only screen readers can access.

Links

The rotor menu will list every single link on a page. Since links are presented in a list according to their text, they will lack some important context if not labeled effectively. Alternatively, a user might choose to use the tab key to navigate through each of the links on the page.

While a sighted user might gather some context by quickly glancing at the link’s surrounding content or UI elements, a screen reader would only be able to focus on the link text as the user attempts to navigate each of the links. They would have to perform additional work to get enough context to understand what the link was going to do.

For example, let’s say your UI included a set of cards for each of your 20 team members, and each card included a link that reads “view details” and opens a page with more information about that person. For a sighted user, the UI might be perfectly sufficient. Each card is nicely contained by a border, and inside that border is a name, maybe a photo, and the “view details” link. The sighted user would likely understand exactly what happens when they click the link.

In the rotor menu, this is utterly unhelpful. The links section will present 20 instances of “view details” in a row. Likewise, for someone tabbing across those links outside the rotor menu, they would hear “view details” over and over. They would have to read through some of the surrounding content to try to understand where each “view details” link might point. This can also become increasingly confusing if the link appeared before the name (which gets into the concept of “meaningful order,” discussed in future installments).

<div class="card">
<header class="header">
<h2>Jared Cunha</h2>
</header>
...
<div class="card-footer">
<a href="#" class="button">View details</a>
</div>
</div>
A rotor menu contain links with insufficient names. There are four links in the menu, each labelled as “View details”. Behind the rotor menu is a set of UI cards where the visual design makes clear what will happen when each “View details” link is clicked.
For each of the cards depicted behind the rotor, sighted users will have no difficulty determining what happens when they click the “View details” button. In the rotor menu, it is impossible to know the difference between the links.

To improve the experience for people with a visual impairment, you can include extra text that will only be available to screen readers. This also applies if the HTML element is a <button> or role="button" is in use. However, any element described as a button will populate the rotor menu’s Form Controls section.

<div class="card">
<header class="header">
<h2>Jared Cunha</h2>
</header>
...
<div class="card-footer">
<a href="#" class="button">View details <span class="screen-reader-only">about Jared Cunha</span></a>
</div>
</div>
A rotor menu contain links with helpful names. There are four links in the menu, one labelled as “View details about Jared Cunha”, another labelled as “View details about Angela (Palm) Hopkins,” another labelled as “View details about Eduardo Ortiz,” and another labelled as “View details about Ashleigh Axios”. Behind the rotor menu is a set of UI cards where the visual design makes clear what will happen when each “View details” link is clicked.
By adding text available only to screen to readers, we provide clarity to each link without cluttering the visual presentation for sighted users.

Best Practices for Product Teams

The following best practices will help your team optimize the user experience for people with visual impairments:

  • Think about how hidden text can add clarity to link text, especially when the link text is repetitive in the UI. Be sure the hidden text is placed at the end of the text that appears in the UI.
  • Don’t use repetitive link text if the links point to different locations.
  • Indicate when links will download a file using either “Download” or “(PDF)” in the link text.
  • Always link phone numbers. Use an aria-labelfor phone numbers, adding spaces between each number so that a screen reader announces them more clearly. For example, <a href="tel:555-555-5555" aria-label="5 5 5 — 5 5 5 — 5 5 5 5">555-555-5555</a>.
  • In general, write link text that makes sense in isolation, both on the page and inside the rotor menu.

Form Controls

The rotor menu will also display all form controls on your page. These can include any type of input, select box, text area, or button (including any type="button"that wouldn’t submit a form, but serve as a UI control). Here, each form element in the rotor menu is displayed by its label.

Form controls can be required, invalid, disabled, or read-only. If you are only visually styling those attributes, it is impossible to tell which form fields include these attributes. The rotor menu will provide the value before the label. Note that in a real-world application, the value of an input would not indicate if a field was disabled or read-only, as the following examples do.

<label for="input-type-text">Input 1</label>
<input id="input-type-text" type="text">
<label for="input-type-text2">Input 2 <span title="required">*</span></label>
<input id="input-type-text2" type="text">
<div class="form-group form-group--error">
<label class="label--error" for="input-error">Input 3</label>
<span class="error-message" id="input-error-message">Helpful error message</span>
<input class="input--error" id="input-error" type="text" aria-describedby="input-error-message">
</div>
<label class="label--disabled" for="input-type-text4">Input 4</label>
<input class="input--disabled" id="input-type-text4" value="this is disabled" type="text">
<label class="label--readonly" for="input-type-text5">Input 5</label>
<input class="input--readonly" id="input-type-text5" value="this is readonly" type="text">
Rotor menu listing form controls where the HTML attributes are not applied, and therefore, not present in the rotor, so there is no way to tell which form fields have errors, are disabled, or read-only. Behind the rotor shows the form fields where in the visual design presentation, these states are clear.
Using CSS alone to style form fields will not convey important information to the rotor menu.

If you were scanning through the page on the rotor menu, could you tell which fields were required, had errors, or were disabled? Using HTML attributes, each field’s state is properly conveyed in the rotor menu. In the updated example below, we can assume that the class selectors were changed to attribute selectors to provide visual styling.

<label for="input-type-text">Input 1</label>
<input id="input-type-text" type="text">
<label for="input-type-text2">Input 2 <span title="required">*</span></label>
<input id="input-type-text2" type="text" required>
<div class="form-group form-group--error">
<label class="label--error" for="input-error">Input 3</label>
<span class="error-message" id="input-error-message">Helpful error message</span>
<input id="input-error" type="text" aria-describedby="input-error-message" aria-invalid="true">
</div>
<label class="label--disabled" for="input-type-text4">Input 4</label>
<input id="input-type-text4" value="this is disabled" type="text" disabled>
<label class="label--readonly" for="input-type-text5">Input 5</label>
<input id="input-type-text5" value="this is readonly" type="text" readonly>
Rotor menu showing Form Controls section where attributes such as required, invalid, disabled, and readonly are convey properly. Behind the rotor is a visual depiction of the form fields.
When we use the appropriate HTML attributes, the rotor will convey to use important characteristics about the form fields.
  • Standard text fields will be read as “edit text.”
  • Read-only text fields will be read as “text” when using the readonly attribute.
  • Required fields will get read as “required” when using the required attribute.
  • Disabled fields will get read as “dimmed” when using the disabled attribute.
  • Invalid fields will get read as “invalid” when using the aria-invalid="true" attribute.

Best Practices for Product Teams

A few things to consider when programming form controls for accessibility:

  • Make sure all form controls are properly labeled.
  • Ensure attribute information is conveyed similarly for sighted and visually impaired users alike.
  • Don’t rely solely on ARIA attributes. Make sure that sighted users can clearly understand these attributes as well.

Tables

The rotor menu also provides a list of every table on the page. Since we’re focused on the rotor menu, we will not be getting into complex table examples here. In addition to semantic markup, one thing every table needs is an accessible name. Failure to provide an accessible name may not generate an error in some tools. But without one, the rotor will outline the table section as follows:

  • “3 columns 5 rows”
  • “2 columns 4 rows”
<h4>Top documents</h4>
<table>
...
</table>
<h4>Store hours</h4>
<table>
...
</table>
Rotor menu on Tabels section with two unnamed tables: “3 columns, 5 rows” and “2 columns, 4 rows.” Behind the rotor are two tables where the visual presentation sufficiently creates names for the tables, but the implementation is not accessible.
Similar to ARIA landmarks, it is impossible to determine the contents of each of the tables without an accessible name.

Note that using <h4> + <table> will not give the table a proper name in the rotor menu. You must name it with <caption>, aria-label, or aria-labelledby. This will give the table a name in the rotor menu, and that name will also be announced when the user navigates to the table. With a name, the rotor menu will now list:

  • “Top documents 3 columns, 5 rows”
  • “Store hours 2 columns, 4 rows”
<table>
<caption>Top documents</caption>
...
</table>
<table>
<caption>Store hours</caption>
...
</table>
Rotor menu in the Tables section listing two captioned tables, so their names are conveyed. Behind the rotor are two tables with no changes to the visual design in the previous example.
Using an accessible name for each table, we can convey important information about their contents to screen readers.

Best Practices for Product Teams

The following best practices will help your team optimize the user experience for people with visual impairments:

  • Every table should have a caption.
  • The caption must be included in any design, and the developer must properly associate the table with a <caption>, aria-label, or aria-labelledby.

Summary

Visually impaired users rely on the rotor menu as both a way to quickly scan important parts of a web page and as an important, in-page navigational tool. Writing semantic HTML and providing helpful names will ensure that the content in this menu is conveyed in the same way as your visual design presentation. The demos presented in this article were limited in scope in order to illustrate key concepts. On any full web page, there will be substantially more items for a user to sift through, which is why naming is so critical to the user experience.

While this article offers suggestions to improve the user experience for assistive technology users, you should make sure to include people who rely on assistive technology as part of your usability testing plan. Support your users by writing semantic markup and do not use accessibility overlays. Additionally, your website should include a link to an accessibility statement on every page where users can report any accessibility issues.

About Jared

Jared Cunha is Director of Product Engineering at Coforma. He has over 15 years of experience working on digital products in fields ranging from online publications to e-commerce to Federal government. He has contributed to the U.S. Web Design System, and his work has been seen and used by tens of millions of people. He works closely with design teams, helping to ensure technical feasibility concerns are met, user needs are properly implemented in the UI, and that accessibility considerations are supported throughout the project development lifecycle.

About Coforma

Coforma works with the government and private sector to craft creative digital solutions and build technology products that improve people’s lives. We’ve honed a modern, agile, user-centered approach that elevates human needs through thoughtfully-designed systems and products. We’re dedicated to reshaping the way communities access and utilize technology products. Together.

Visit us at coforma.io.

--

--