Skip to content

Don’t use a listbox for README table of contents #1371

@knowler

Description

@knowler

The use of the listbox pattern for the README table of contents (TOC) is both broken for assistive tech and, in my opinion, the wrong tool for the task.

Instead, we should use a button with an associated popover that has a list of links. The markup would look something like this:

<!-- “navigation” landmark labelled “README table of contents” -->
<nav aria-labelledby=readme-toc-toggle>
  <button id=readme-toc-toggle popovertarget=readme-toc popovertargetaction=toggle>
    README table of contents<!-- visually hidden with the icon -->
  </button>
  <!-- I don’t think we need to label the list as the context would make it redundant -->
  <ul id=readme-toc popover>
    <li><a href=#user-content-nuxt aria-current=true>Nuxt</a><!-- current hash-matching link -->
    <li><a href=#user-content-table-of-contents>Table of contents</a><!-- inception -->
    <li><a href=#user-content-getting-started>🚀 Getting Started</a>
    <!-- etc. -->
  </ul>
</nav>

There are several benefits to this approach:

  1. It’s more appropriate semantically and it avoids a lot of complexity for accessibility which means it’s less prone to break assistive tech.
  2. popovertarget/popoveraction on a <button> makes it a collapse/expand button out-of-the-box (i.e. it implicitly sets aria-expanded for us).
  3. We can leverage :popover-open (utility variant open:) for styling the popover when it’s open.
  4. We don’t need to worry about aria-activedescendant and the complications that brings for accessibility and styling.
  5. If we set scroll-behavior: smooth on the :root we can just let the links do their thing.
    • It would be good to set some scroll-margin for the README’s headings or maybe scroll-padding on :root would be better?
  6. All of this doesn’t require any JavaScript.

In other words, there is a lot that was being done with JS that we can just let the platform do for us.

We can reserve JS for enhancements like:

  1. Maybe some focus management. Popovers don’t move their focus to the popover by default, but I know that GitHub’s README TOC does do some focus trapping (i.e. so that the focus wraps from the start to the end, vice versa).
  2. Set aria-current=true on whatever link matches the hash of the page.

Metadata

Metadata

Assignees

Labels

a11yRelated to accessibility and inclusionfrontFrontend, Design

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions