quarto-dev / quarto-dev/quarto-cli
a11y: navbar and sidebar tools declared with only an `icon:` have no accessible name
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 6k
- Forks
- 458
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 41
Description
The documented way to declare navbar and sidebar tools uses icon: alone, with no text:. That renders links with an empty accessible name, which axe-core reports as link-name.
Taking the example straight from https://quarto.org/docs/websites/website-navigation.html#navbar-tools:
project:
type: website
website:
title: "Tools repro"
navbar:
left:
- href: index.qmd
text: Home
tools:
- icon: bluesky
href: https://bsky.app
- icon: github
menu:
- text: Source Code
href: https://code.com
- text: Report a Bug
href: https://bugs.com
format:
html:
axe:
output: json
produces
<a href="https://bsky.app" title="" class="quarto-navigation-tool px-1" aria-label=""><i class="bi bi-bluesky"></i></a>
<a href="" title="" id="quarto-navigation-tool-dropdown-0" class="quarto-navigation-tool dropdown-toggle px-1" data-bs-toggle="dropdown" aria-expanded="false" role="link" aria-label=""><i class="bi bi-github"></i></a>
The icon is drawn by a class on an empty <i>, so there is no text node to fall back on. Chrome's accessibility tree announces both as link "", and axe-core reports link-name (serious, wcag2a / wcag244 / wcag412) on three nodes for that config: the navbar tool, the navbar dropdown tool, and the sidebar tool. Sidebar tools go through the same template, so website: sidebar: tools: is affected the same way, and the sidebar example in the docs has the same shape.
aria-label="" is worse than no attribute at all, since an empty aria-label blanks the name rather than letting anything else supply one. Both attributes are interpolated from tool.text, which is unset here:
Authors have little reason to set text: on a tool, since it never renders as visible text, only as the title tooltip. aria-label: is accepted on the item and does fix it, but nothing points authors there. Note the same lines already avoid emitting empty rel and target, so title and aria-label look like they were just missed in that pass.
We could omit both attributes when there is no value, and fall back to a name derived from the icon when neither text: nor aria-label: is given, so that the documented configuration produces a named link by default.
Related: #14380 and #14655 are the same axe rule on different elements, and #14373 collects a batch of axe-core findings on Quarto sites.
cc @cwickham as I don't know if you spotted this one, but 🤖 reported it to me while testing
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/resources/projects/website/templates/navtools.ejs at the linked lines, then compare the navbar and sidebar tool examples in the website navigation documentation. Reproduce the icon-only configuration with the shown axe output and verify that the resulting links have meaningful accessible names without empty title or aria-label attributes; done means the link-name violations are gone for navbar and sidebar tools.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- accessibility, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100