quarto-dev / quarto-dev/quarto-cli

a11y: navbar and sidebar tools declared with only an `icon:` have no accessible name

Open
#14,828 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accessibility bug
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:

https://github.com/quarto-dev/quarto-cli/blob/2117a09798cba666b531b76642ee154e201b7d5c/src/resources/projects/website/templates/navtools.ejs#L26-L46

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.