Skip to main content

Tagged “aria”

How to build an accesssible autocomplete

At work there are plans afoot to reconcile various differing Autocomplete implementations into a single, reusable component. So far there’s been a written audit presenting all instances and how they differ in functional and technical respects. There’s also been design work to identify visual commonalities and avoid future inconsistencies. I’d now like to add another perspective: an investigation into which HTML materials and (if necessary) ARIA supplements are appropriate to ensure we build something accessible and resilient.

My experience is that to achieve the right result, HTML semantics and related concerns can’t just follow and bend to spec and visual design goals, but rather must influence the setting of those goals.

I’ll flesh out my findings in due course, but for now here are the key resources I’ve identified and plan to dig deep into.

Adrian Roselli’s article Stop Using ‘Drop-down’. To summarise the options of interest:

  • ARIA Listbox lets you create a DIY thing that has the same roles and semantics as a <select> but where you have greater stylistic control. There are different ways to implement a Listbox.
  • Datalist is the native HTML version of a combo box. A combo box is essentially a <select> with a text field. Datalist is announced by screen readers in different ways but as far as I can gather these are quirky rather than terrible. I found a nice Twitter thread on DataList which not only shows off its function but also includes a promising accessibility-related comment from Patrick H Lauke of Tetralogical. The drawback, because Datalist is native HTML, is that its options are not stylelable.
  • ARIA Combobox is a pattern that combines ARIA combobox, textbox and listbox roles, and the benefit it brings is to allow a level of custom design that you couldn’t achieve with Datalist.
  • Autocomplete (not to be confused with the HTML autocomplete attribute) describes a control which provides users with suggestions that may not be available in the DOM already… for example when you fetch options via Ajax in reponse to what the user types.

With regard to Autocomplete, Adrian points to Adam Silver’s Building an accessible autocomplete control.

And for advice on whether or not to go with a native select or a custom control, and how best to implement listbox and combobox if that’s your choice, Adrian points to the following resources from Sarah Higley:

I also see that GOV.UK have marked a possible Autocomplete component as one of their next priorities to review. Their Autocomplete discussion thread includes examples and research and will be really helpful.

The ARIA presentation role

I’ve never properly understood when you would need to use the ARIA presentation role. This is perhaps in part because it is often used inappropriately, for example in situations where aria-hidden would be more appropriate. However I think the penny has finally dropped.

It’s fairly nuanced stuff so I’ll forgive myself this time!

You might use role=presentation in JavaScript which progressively enhances a basic JS-independent HTML foundation into a more advanced JS-dependent experience. In such cases you might want to reuse the baseline HTML but remove semantics which are no longer appropriate.

As an example, Inclusive Components Tabbed Interfaces starts with a Table of Contents marked up as an unordered list of links. However in enhanced mode the links take on a new role as tabs in a tablist so role=presentation is applied to their containing <li> elements so that the tab list is announced appropriately and not as a plain list.

Building the main navigation for a website (on web.dev)

learn about semantic HTML, accessibility, and how using ARIA attributes can sometimes do more harm than good.

Alongside all the sound accessibility and hiding-related advice, I also found Manuel’s approach to progressive enhancement interesting. Rather than i) include a hamburger button directly in the DOM and set its initial state to hidden; or ii) create the button element with JavaScript, he instead nests the button in a template element then clones that element with JavaScript. He later tweeted his rationale for this approach:

If JS doesn't work, the markup inside the template won't be rendered on screen and it's more convenient to prepare the markup upfront instead of using document.createElement().

The ability to prepare complex, JS-dependent component markup upfront in declarative HTML rather than recreating it in JavaScript is a compelling argument for his approach. Especially so if you don’t work in JS framework-based systems therefore your components are not written in JavaScript.

Broken Copy, on a11y-101.com

Here’s an accessibility tip that’s new to me. When the content of a heading, anchor, or other semantic HTML element contains smaller “chunks” of span and em (etc), the VoiceOver screen reader on Mac and iOS annoyingly fails to announce the content as a single phrase and instead repeats the parent element’s role for each inner element. We can fix that by adding an inner “wrapper” element inside our parent and giving it role=text.

Make sure not to add this role directly to your parent element since it will override its original role causing it to lose its intended semantics.

The text role is not yet in the official ARIA spec but is supported by Safari.

(via @Seraphae and friends on Twitter)

Should I use the HTML5 section element and if so, where?

Unlike other HTML5 elements such as header, footer and nav, it’s never been particularly clear to me when is appropriate to use section. This is due in large part to many experts having expressed that it doesn’t quite work as intended.

I like HTMHell’s rule-of-thumb regarding section:

If you’re not sure whether to use a <section>, it’s probably best to avoid it.

They go on to recommend that it’s much more important to create a sound document outline. That phrase can be confusing because of the related history of the browser document outline algorithm (or lack thereof) but I think what the author means here is to use and nest headings logically because that alone will give you a “document outline” and also helps AT users scan and skip around the page.

Relatedly: don’t let the original intended use of section tempt you to put multiple H1s on a page in the vain hope that browsers and assistive technology will interpret their nesting level to handle hierarchy appropriately. That would rely on on a document outline algorithm but no browser implements document outlining.

One sensible application of section is to provide additional information to screen reader users about the semantic difference between two adjoining content areas, when that distinction is otherwise only being made visually with CSS.

Here’s an example. Smashing Magazine’s blog articles begin with a quick summary, followed by a horizontal line separating the summary from the article proper. But the separator is purely decorative, so if the summary were wrapped in a div then a screen reader user wouldn’t know where it ends and the article begins. However by instead wrapping the summary in <section aria-label="quick summary">:

  • our wrapper has the built-in ARIA role of region. A region is a type of generic landmark element, and as a landmark a screen reader user will find it listed in a summary of the page and can navigate to it easily.
  • by giving it an accessible name (here via aria-label) it will be announced by a screen reader, with “Quick summary region” before and “Quick summary region end” after.

Update 07/11/22

Adrian Roselli’s twitter thread on section is gold. Here’s what I’ve gleaned from it:

The reason you would use a section element for accessibility purposes is to create a region landmark. If you are using headings properly, in most cases your content is already well-structured and will not require a region landmark. If you do need a section, note that from an accessibility perspective using the section tag alone is meaningless without providing an accessible name. To provide this, ensure your section has a heading and connect the section to that using aria-labelledby.

You can use section without the above measures and it will not harm users. But be aware it’s aiding your developer experience only, because it’s not helping users. And it may also mislead you and others into thinking you are providing semantics and accessibility which in reality you are not.

References:

Accessible interactions (on Adactio)

Jeremy Keith takes us through his thought process regarding the choice of link or button when planning accessible interactive disclosure elements.

A button is generally a solid choice as it’s built for general interactivity and carries the expectation that when activated, something somewhere happens. However in some cases a link might be appropriate, for example when the trigger and target content are relatively far apart in the DOM and we feel the need move the user to the target / give it focus.

For a typical disclosure pattern where some content is shown/hidden by an adjacent trigger, a button suits perfectly. The DOM elements are right next to each other and flow into each other so there’s no need to move or focus anything.

However in the case of a log-in link in a navigation menu which—when enhanced by JavaScript—opens a log-in form inside a modal dialogue, a link might be better. In this case you might use an anchor with a fragment identifier (<a href="#login-modal">Log in</a>) pointing to a login-form far away at the bottom of the page. This simple baseline will work if JavaScript is unavailable or fails, however when JavaScript is available we can intercept the link’s default behaviour and enhance things. Furthermore because the expectation with links is that you’ll go somewhere and modal dialogues are kinda like faux pages, the link feels appropriate.

While not explicit in the article, another thing I take from this is that by structuring your no-JavaScript experience well, this will help you make appropriate decisions when considering the with-JavaScript experience. There’s a kind of virtuous circle there.

How to hide elements on a web page

In order to code modern component designs we often need to hide then reveal elements. At other times we want to provide content to one type of user but hide it from another because it’s not relevant to their mode of browsing. In all cases accessibility should be front and centre in our thoughts. Here’s my approach, heavily inspired by Scott O’Hara’s definitive guide Inclusively Hidden.

Firstly, avoid the need to hide stuff. With a bit more thought and by using existing fit-for-purpose HTML tools, we can perhaps create a single user interface and experience that works for all. That approach not only feels like a more equal experience for everyone but also removes margin for error and code maintenance overhead.

With that said, hiding is sometimes necessary and here are the most common categories:

  1. Hide from everyone
  2. Hide visually (i.e. from sighted people)
  3. Hide from Assistive Technologies (such as screen readers)

Hide from everyone

We usually hide an element from everyone because the hidden element forms part of a component’s interface design. Typical examples are tab panels, off-screen navigation, and modal dialogues that are initially hidden until an event occurs which should bring them into view. Initially these elements should be inaccessible to everyone but after the trigger event, they become accessible to everyone.

Implementation involves using JavaScript to toggle an HTML attribute or class on the relevant element.

For basic, non-animated show-and-hide interactions you can either:

  1. toggle a class which applies display: none in CSS; or
  2. toggle the boolean hidden attribute, which has the same effect but is native to HTML5.

Both options work well but for me using the hidden attribute feels a little simpler and more purposeful. My approach is to ensure resilience by making the content available in the first instance in case JavaScript should fail. Then, per Inclusive Components’ Tabs example, JavaScript applies both the “first hide” and all subsequent toggling.

Here’s some CSS that supports both methods. (The hidden attribute doesn’t strictly need this but it’s handy to regard both options as high-specifity, “trump-everything-else” overrides.)

.u-hidden-from-everyone, 
[hidden] {
  display: none !important;
}

For cases where you are animating or sliding the hidden content into view, toggle the application of CSS visibility: hidden because this also removes the element from the accessibility tree but unlike display, can be animated. Note that with visibility: hidden the physical space occupied by the element is still retained, therefore it’s best to pair it with position: absolute or max-height: 0px; overflow: hidden to prevent that “empty space while hidden” effect. For example:

.off-canvas-menu {
  visibility: hidden;
  position: absolute;
  transform: translateX(-8em);
  transition: 250ms ease-in;
}
[aria-expanded="true"] + off-canvas-menu {
  visibility: visible;
  transform: translateX(0);
  transition: visibility 50ms, transform 250ms ease-out;
}

Hide visually (i.e. from sighted people)

We’ll usually want to hide something visually (only) when its purpose is solely to provide extra context to Assistive Technologies. An example would be appending additional, visually-hidden text to a “Read more” link such as “about Joe Biden” since that would be beneficial to screen reader users.

We can achieve this with a visually-hidden class in CSS and by applying that class to our element.

.visually-hidden:not(:focus):not(:active) {
  clip: rect(0 0 0 0); 
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap; 
  width: 1px;
}

Essentially this hides whatever it’s applied to unless it’s a focusable element currently being focused by screen reader controls or the tab key, in which case it is revealed.

Note that if adding to link text to make it more accessible, always append rather than inserting words into the middle of the existing text. That way, you avoid solving an accessibility for one group but creating another for another group (Dragon speech recognition software users).

Visually hidden until focused

There are other CSS approaches to hiding visually. One approach is to not only add position: absolute (removing the element from the document flow) but also position it off-screen with left: -100vw or similar. The use case for this approach might be when you want your visually hidden element to support being revealed and for that reveal to occur via a transition/animation from off-screen into the viewport. See Scott O’Hara’s off screen skip-links example.

Hide from Assistive Technologies (such as screen readers)

We sometimes hide visual elements from Assistive Technologies because they are decorative and have accompanying text, for example a “warning” icon with the text “warning” alongside. If we did not intervene then Assistive Technologies would read out “warning” twice which is redundant.

To achieve this we can apply aria-hidden="true" to our element so that screen readers know to ignore it. In the following examples we hide the SVG icons within buttons and links, safe in the knowledge that the included “Search” text is providing each interactive element with its accessible name.

<button>
  <svg aria-hidden="true" focusable="false"><!--...--></svg>
  Search
</button>

<a href="/search">
  <svg aria-hidden="true" focusable="false"><!--...--></svg>
  Search
</a>

Reference: Contextually Marking up accessible images and SVGs

The difference between aria-label and aria-labelledby (Tink - Léonie Watson)

The aria-label and aria-labelledby attributes do the same thing but in different ways. Sometimes the two attributes are confused and this has unintended results. This post describes the differences between them and how to choose the right one.

The key takeaways for me were:

  • Many HTML elements have an accessible name (which we can think of as its “label”) and this can be derived from the element’s content, an attribute, or from an associated element;
  • for aria-labelledby, use the id of another element and that will then use that element’s text as your first element’s accessible name;
  • use native HTML over ARIA where possible, but when you need ARIA it’s better to reuse than duplicate so if an appropriate label already exists in the document use aria-labelledby; otherwise use aria-label;
  • an ARIA attribute will trump any other accessible name (such as the element’s content)
  • there are some elements on which these ARIA attributes do not work consistently so check these before using.

Sign-in form best practices (on web.dev)

Sam Dutton advises how to use cross-platform browser features to build sign-in forms that are secure, accessible and easy to use.

The tips of greatest interest to me were:

  • on using autocomplete="new-password" on registration forms and autocomplete="current-password" on sign-in forms to tap into browser password suggestion and password manager features;
  • on how best to provide “Show Password” functionality; and
  • on using aria-describedby when providing guidance on password rules.

HTML: The Inaccessible Parts (daverupert.com)

Here’s Dave Rupert, frustratedly rounding up the accessibility shortfalls in browser implementations of native HTML elements.

I’ve always abided in the idea that “HTML is accessible by default and then we come along and mess it up”. But that’s not always the case. There are some cases where even using plain ol’ HTML causes accessibility problems.

(via @jamesmockett)

Using aria-current is a win-win situation

The HTML attribute aria-current allows us to indicate the currently active element in a sequence. It’s not only great for accessibility but also doubles as a hook to style that element individually.

By using [aria-current] as your CSS selector (rather than a .current class) this also neatly binds and syncs the way you cater to the visual experience and the screen reader experience, reducing the ability for the latter to be forgotten about.

As Léonie Watson explains, according to WAI-ARIA 1.1 there are a number of useful values that the aria-current attribute can take:

  • page to indicate the current page within a navigation menu or pagination section;
  • step for the current step in a step-based process;
  • date for the current date.
  • time for the current time.

I’ve been using the aria-current="page" technique on a couple of navigation menus recently and it’s working well.

Also: my thanks go to Ethan Marcotte, David Kennedy and Lindsey. Ethan recently suggested that the industry should try harder regarding accessibility and recommended subscribing to David Kennedy’s a11y Weekly newsletter. I duly subscribed (it’s great!) and one of the issues linked to Lindsey’s article An Introduction to ARIA states in which I learned about aria-current.

How to control SVG icon size and colour in context

A while back I read a great SVG icon tip from Andy Bell which I’d been meaning to try and finally did so today. Andy recommended that for icons with text labels we set the width and height of the icons to 1em since that will size them proportionately to the adjacent text and additionally lets us use font-size to make any further sizing tweaks.

As previously mentioned, I’ve recently been working on my SVG skills.

Andy Bell’s SVG icon-sizing technique is really clever and feels like it adds lots of flexibility and future-friendliness so I was keen to try it out.

Here’s how it works.

The HTML:

<a class="call-to-action" href="/">
  <span>I’m a link</span>
    <svg 
    class="cta-icon" 
    aria-hidden="true" 
    width="1em" 
    height="1em" 
    viewBox="0 0 14 13" 
      xmlns="http://www.w3.org/2000/svg">
      <path 
      fill="currentColor" 
      fill-rule="evenodd" 
        d="M3.49.868l7.683 3.634a2 2 0 0 1 .052 3.59l-7.682 3.913a2 2 0 0 1-2.908-1.782V2.676A2 2 0 0 1 3.49.868z">
    </path>
  </svg>
</a>

<a class="call-to-action call-to-action-alt" href="/">
  <span>I’m a large link</span>
    <svg 
    class="cta-icon" aria-hidden="true" 
    width="1em" height="1em" 
    viewBox="0 0 14 13" 
      xmlns="http://www.w3.org/2000/svg">
      <path 
      fill="currentColor" 
      fill-rule="evenodd" 
        d="M3.49.868l7.683 3.634a2 2 0 0 1 .052 3.59l-7.682 3.913a2 2 0 0 1-2.908-1.782V2.676A2 2 0 0 1 3.49.868z">
    </path>
  </svg>
</a>

The CSS:

a { color: rgb(183, 65, 14); }

a:hover { color: #6A2000; }

.call-to-action {
  display: inline-flex;
  align-items: center;
  font-weight: bold;
}

.call-to-action-alt {
  font-size: 2rem; 
}

.cta-icon {
  margin-left: .5em;
  font-size: .8em;
}

Here are my key takeaways:

  • By applying width and height of 1em to our icon it is predictably sized by default.
  • It can now have its size further tweaked in CSS using font-size, for example with ems (where 1em = the font-size of the parent anchor element).
  • This technique requires the viewbox attribute being present on the svg.
  • Apply the width and height =1em as inline attributes on the svg. We could apply them using CSS, however the inline approach avoids potentially massive icons showing in cases where CSS doesn’t load.
  • To get the colour matching, apply fill="currentColor" as an inline attribute on the svg’s path.
  • Now, when you apply a hover colour to the anchor in CSS, the icon will just pick that up. Nice!
  • Applying inline-flex to the anchor makes the vertical-alignment of text and icon easier.
  • Apply aria-hidden to the icon because it’s mainly decorative so we don’t want it read out by screen readers.

And here’s a demo I created to test-drive the technique.

See all tags.

External Link Bookmark Note Entry Search