Skip to content

fix: hide axis ticks from aria since they are just adding noise - #2018

Merged
mbostock merged 3 commits into
observablehq:mainfrom
domoritz:dom/aria-axes
Mar 13, 2024
Merged

mbostock merged 3 commits into
observablehq:mainfrom
domoritz:dom/aria-axes

Conversation

@domoritz

@domoritz domoritz commented Mar 12, 2024 •

Copy link
Copy Markdown
Contributor

Fixes #2019

  • Hide axis ticks since they just add noise (VoiceOver just exposes them as "image")
  • Keep axis labels as the default. In the future, it would be great if axes actually described the scale range (as done by default in Vega-Lite). e.g. "0% to 13%".

I tested this with http://localhost:8008/?test=letterFrequencyBar.

@mbostock
mbostock enabled auto-merge (squash) March 13, 2024 00:00
@mbostock
mbostock merged commit 21bfe7f into observablehq:main Mar 13, 2024
cwickham added a commit to quarto-dev/quarto-web that referenced this pull request Oct 2, 2026
* Seed _axe-baseline.json with the one carried-forward entry

Re-checked all 27 entries from the old harness baseline
(origin/feat/axe-a11y-harness:_tools/axe/baseline.json) against the
2026-09-15 quarto-web 1.11.4 scan. Only scrollable-region-focusable ::
#cb still has both a live signature and a note that still holds
(quarto-cli#14378, still open). Three entries were fixed upstream
(#14615, #14376) and no longer appear. The remaining 23 carried empty
notes with no recorded reasoning, so they're held open for a fresh
re-triage (accessibility repo strand ax-xmy5f5qm) rather than carried
forward blind.

* Accept the dygraphs axis-label contrast on the htmlwidgets page

dygraph.js sets the axis-label color with an inline style, so no CSS can
override it. dygraph.js >= 2.0 moves it into a stylesheet rule, but the R
dygraphs package still bundles 1.1.1 (rstudio/dygraphs#241). Scoped to
htmlwidgets.html: the same signature on penguins-preview.html is a real
Quarto defect that must stay visible.

* Accept the Observable Plot g[aria-label] findings as third-party

Plot puts an aria-label with no role on the <g> of every mark and axis.
20 signatures in two groups:

- 10 axis-tick and grid signatures are fixed in Plot 0.6.14
  (observablehq/plot#2018). Quarto bundles Plot 0.6.11, so these wait on
  quarto-cli#14934. Prune them when Quarto updates Plot.
- 10 data-mark signatures still occur in Plot 0.6.17. Plot labels marks
  on purpose (observablehq/plot#944); the open request for a role is
  observablehq/plot#1760.

* Accept the Observable Inputs unlabeled slider and checkbox findings as third-party

Inputs.range puts its <label for> on the number box only, so the slider
has no accessible name even when `label` is set. Inputs.table row and
header checkboxes have no label, and no option adds one. Inputs 0.12.0
has the same markup, and no upstream issue reports either defect.

The two .oi-3a86ea-input signatures are site-wide; the selector becomes
.inputs-3a86ea-input when Quarto updates Inputs (quarto-cli#14934). The
four generic signatures are scoped to their pages, so a new unlabeled
input elsewhere still shows as new.

* Accept the margin-citation aria-required-parent finding as upstream

quarto-cli#14755: Quarto relocates bibliography entries to the margin but
drops the role="list" wrapper they need, leaving role="listitem" orphaned.
1 instance on docs/authoring/article-layout.html.

* Accept the callout disclosure ARIA findings as upstream

quarto-cli#4934: collapsed callouts use a plain <div aria-expanded> instead
of the ARIA disclosure pattern (button + aria-controls), open since 2023.
3 signatures / 13 instances across brand, callouts, front-matter, the three
manuscript editor pages, github-pages, and the get-started editor pages.

* Accept the placeholder-shortcode alt findings as upstream

quarto-cli#14769: {{< placeholder >}} builds its <img> from pandoc.Image
with an always-empty caption, so no alt attribute reaches the output.
2 instances on docs/authoring/placeholder.html, scoped to that page --
the broader p > .img-fluid signature also covers real content images on
other pages that still need alt text of their own.

* Accept the leaflet marker-icon and attribution findings as third-party

leaflet.js sets role="button" and tabindex="0" on marker icons that also
carry alt="" (implicit presentation role), and its attribution control's
CSS isn't dark-mode aware. 7 signatures / 9 marker instances + 2 contrast
findings (2 instances each) across docs/interactive/index,
docs/interactive/widgets/{htmlwidgets,jupyter}, the revealjs demo, and the
three leaflet maps on docs/authoring/article-layout. No upstream issue —
this is leaflet's own markup and CSS, not Quarto's.

* Accept the knitr::kable() and Arquero table findings as third-party

knitr::kable() leaves the row-name corner cell as an empty <th> by
design, not oversight: yihui/knitr#1747, merged as PR #2500 on
2026-09-19, added scope="col"/scope="row" to kable's other header cells
but explicitly kept the corner cell blank and unscoped. 5 signatures / 7
instances across notebook-embed, penguins(-preview), three kable()
examples on article-layout, and the revealjs demo's Data tab.

Arquero's table viewer hardcodes background: #fff via inline JS style, so
its sticky header text fails contrast in dark mode (1 signature, 22
instances, reused on both the arquero example and libraries pages).

Each of the 5 kable entries repeats the full note, so the context
survives if any one entry is pruned.

* Accept the code-preview frame-title findings as upstream

The 35 code-preview iframes have no title (quarto-cli#14770). They clear
when quarto-cli#14933 ships, because fix/code-preview-titles already sets
code-preview-title on every preview.

* Accept the revealjs meta-viewport finding as upstream

* Accept the scrollable-region findings that quarto-cli#14816 fixes as upstream

* Accept the revealjs line-highlight fade findings as upstream

* Accept the revealjs line-number anchor findings as upstream

* Accept the vega-embed actions-menu summary-name findings as third-party

* Accept the Leaflet ESDIS attribution link findings as third-party

* Accept the Arquero notebook table-view scrollable-region finding as third-party

* Accept the revealjs scrollable-region findings as upstream quarto-cli#14817

* Accept the revealjs link and tab contrast findings as upstream quarto-cli#14962 and #14963

* Accept the revealjs closed slide-menu contrast finding as a false positive

* Accept the revealjs slide-menu button link-name finding as upstream quarto-cli#14249

* Accept the page landmark findings as upstream quarto-cli#14375, #14968 and #14969

* Accept the revealjs tabindex, nested controls landmark, and Inputs.table header findings

Upstream quarto-cli#14970 and hakimel/reveal.js#3369, and third-party Observable Inputs.

* Accept the background-no-title empty-heading finding as an intentional example

* Accept the embed-header region finding on the second notebook preview page

* Update the article-layout leaflet baseline entries to the IDs refrozen by #2242

The three presentation-role-conflict signatures include the htmlwidget ID of each map. #2242 re-executed docs/authoring/article-layout.qmd, so the frozen IDs changed.

* Tidy baseline notes, group entries by owner, and limit .collapsed to its pages

Notes now read '<type>: <issue-ref>. <description>.' with full org/repo
references and no commentary or links. Entries follow the PR description's
order. aria-allowed-attr :: .collapsed is limited to the four get-started
authoring pages, because .collapsed is the generic Bootstrap class.

* Document the axe baseline note format in the README and a Claude rule
cwickham added a commit to quarto-dev/quarto-web that referenced this pull request Oct 2, 2026
… (#2260)

* Seed _axe-baseline.json with the one carried-forward entry

Re-checked all 27 entries from the old harness baseline
(origin/feat/axe-a11y-harness:_tools/axe/baseline.json) against the
2026-09-15 quarto-web 1.11.4 scan. Only scrollable-region-focusable ::
#cb still has both a live signature and a note that still holds
(quarto-cli#14378, still open). Three entries were fixed upstream
(#14615, #14376) and no longer appear. The remaining 23 carried empty
notes with no recorded reasoning, so they're held open for a fresh
re-triage (accessibility repo strand ax-xmy5f5qm) rather than carried
forward blind.

* Accept the dygraphs axis-label contrast on the htmlwidgets page

dygraph.js sets the axis-label color with an inline style, so no CSS can
override it. dygraph.js >= 2.0 moves it into a stylesheet rule, but the R
dygraphs package still bundles 1.1.1 (rstudio/dygraphs#241). Scoped to
htmlwidgets.html: the same signature on penguins-preview.html is a real
Quarto defect that must stay visible.

* Accept the Observable Plot g[aria-label] findings as third-party

Plot puts an aria-label with no role on the <g> of every mark and axis.
20 signatures in two groups:

- 10 axis-tick and grid signatures are fixed in Plot 0.6.14
  (observablehq/plot#2018). Quarto bundles Plot 0.6.11, so these wait on
  quarto-cli#14934. Prune them when Quarto updates Plot.
- 10 data-mark signatures still occur in Plot 0.6.17. Plot labels marks
  on purpose (observablehq/plot#944); the open request for a role is
  observablehq/plot#1760.

* Accept the Observable Inputs unlabeled slider and checkbox findings as third-party

Inputs.range puts its <label for> on the number box only, so the slider
has no accessible name even when `label` is set. Inputs.table row and
header checkboxes have no label, and no option adds one. Inputs 0.12.0
has the same markup, and no upstream issue reports either defect.

The two .oi-3a86ea-input signatures are site-wide; the selector becomes
.inputs-3a86ea-input when Quarto updates Inputs (quarto-cli#14934). The
four generic signatures are scoped to their pages, so a new unlabeled
input elsewhere still shows as new.

* Accept the margin-citation aria-required-parent finding as upstream

quarto-cli#14755: Quarto relocates bibliography entries to the margin but
drops the role="list" wrapper they need, leaving role="listitem" orphaned.
1 instance on docs/authoring/article-layout.html.

* Accept the callout disclosure ARIA findings as upstream

quarto-cli#4934: collapsed callouts use a plain <div aria-expanded> instead
of the ARIA disclosure pattern (button + aria-controls), open since 2023.
3 signatures / 13 instances across brand, callouts, front-matter, the three
manuscript editor pages, github-pages, and the get-started editor pages.

* Accept the placeholder-shortcode alt findings as upstream

quarto-cli#14769: {{< placeholder >}} builds its <img> from pandoc.Image
with an always-empty caption, so no alt attribute reaches the output.
2 instances on docs/authoring/placeholder.html, scoped to that page --
the broader p > .img-fluid signature also covers real content images on
other pages that still need alt text of their own.

* Accept the leaflet marker-icon and attribution findings as third-party

leaflet.js sets role="button" and tabindex="0" on marker icons that also
carry alt="" (implicit presentation role), and its attribution control's
CSS isn't dark-mode aware. 7 signatures / 9 marker instances + 2 contrast
findings (2 instances each) across docs/interactive/index,
docs/interactive/widgets/{htmlwidgets,jupyter}, the revealjs demo, and the
three leaflet maps on docs/authoring/article-layout. No upstream issue —
this is leaflet's own markup and CSS, not Quarto's.

* Accept the knitr::kable() and Arquero table findings as third-party

knitr::kable() leaves the row-name corner cell as an empty <th> by
design, not oversight: yihui/knitr#1747, merged as PR #2500 on
2026-09-19, added scope="col"/scope="row" to kable's other header cells
but explicitly kept the corner cell blank and unscoped. 5 signatures / 7
instances across notebook-embed, penguins(-preview), three kable()
examples on article-layout, and the revealjs demo's Data tab.

Arquero's table viewer hardcodes background: #fff via inline JS style, so
its sticky header text fails contrast in dark mode (1 signature, 22
instances, reused on both the arquero example and libraries pages).

Each of the 5 kable entries repeats the full note, so the context
survives if any one entry is pruned.

* Accept the code-preview frame-title findings as upstream

The 35 code-preview iframes have no title (quarto-cli#14770). They clear
when quarto-cli#14933 ships, because fix/code-preview-titles already sets
code-preview-title on every preview.

* Accept the revealjs meta-viewport finding as upstream

* Accept the scrollable-region findings that quarto-cli#14816 fixes as upstream

* Accept the revealjs line-highlight fade findings as upstream

* Accept the revealjs line-number anchor findings as upstream

* Accept the vega-embed actions-menu summary-name findings as third-party

* Accept the Leaflet ESDIS attribution link findings as third-party

* Accept the Arquero notebook table-view scrollable-region finding as third-party

* Accept the revealjs scrollable-region findings as upstream quarto-cli#14817

* Accept the revealjs link and tab contrast findings as upstream quarto-cli#14962 and #14963

* Accept the revealjs closed slide-menu contrast finding as a false positive

* Accept the revealjs slide-menu button link-name finding as upstream quarto-cli#14249

* Accept the page landmark findings as upstream quarto-cli#14375, #14968 and #14969

* Accept the revealjs tabindex, nested controls landmark, and Inputs.table header findings

Upstream quarto-cli#14970 and hakimel/reveal.js#3369, and third-party Observable Inputs.

* Accept the background-no-title empty-heading finding as an intentional example

* Accept the embed-header region finding on the second notebook preview page

* Update the article-layout leaflet baseline entries to the IDs refrozen by #2242

The three presentation-role-conflict signatures include the htmlwidget ID of each map. #2242 re-executed docs/authoring/article-layout.qmd, so the frozen IDs changed.

* Tidy baseline notes, group entries by owner, and limit .collapsed to its pages

Notes now read '<type>: <issue-ref>. <description>.' with full org/repo
references and no commentary or links. Entries follow the PR description's
order. aria-allowed-attr :: .collapsed is limited to the four get-started
authoring pages, because .collapsed is the generic Bootstrap class.

* Document the axe baseline note format in the README and a Claude rule

(cherry picked from commit a4b9a81)

Co-authored-by: Charlotte Wickham <charlotte.wickham@posit.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Axis ticks are exposed to screen readers

2 participants