Skip to content

Fix code-line-numbers links having no accessible name#14662

Open
cderv wants to merge 2 commits into
mainfrom
fix/issue-14655
Open

Fix code-line-numbers links having no accessible name#14662
cderv wants to merge 2 commits into
mainfrom
fix/issue-14655

Conversation

@cderv

@cderv cderv commented Jul 8, 2026

Copy link
Copy Markdown
Member

Skylighting's numberSource line-numbering emits an empty <a href="#cbN-n"></a> as the first child of every code line span, drawing the visible number purely via a CSS counter on ::before. Screen readers and axe-core see a focusable link with no discernible text (WCAG 2.4.4/4.1.2 link-name).

Fix

Set aria-label on each line anchor to its visible line number, computed from any counter-reset: source-line N offset so custom startFrom values stay correct. Implemented as a postprocessor pass in htmlFormatPostprocessor (src/format/html/format-html.ts), which revealjs's htmlFormatExtras also inherits, so one pass covers both html and revealjs.

aria-hidden isn't an option here: these anchors are real, focusable fragment links, and aria-hidden on a focusable element is itself an axe violation.

Verified against real axe-core in a browser, now codified as a playwright regression test. On revealjs, the axe report still shows a pre-existing link-name violation from the deck's .slide-menu-button chrome, unrelated to this issue and out of scope here.

Fixes #14655

cderv added 2 commits July 8, 2026 18:14
Skylighting's numberSource line numbering emits an empty <a> per line,
with the visible number drawn purely via a CSS counter on ::before.
Screen readers and axe-core see a focusable link with no discernible
text (WCAG 2.4.4/4.1.2). aria-hidden isn't an option since these
anchors are real, focusable fragment links, and aria-hidden on a
focusable element is itself an axe violation. Instead, set aria-label
to the visible line number, computed from any counter-reset offset so
custom startFrom values stay correct.

Implemented as a postprocessor pass in htmlFormatPostprocessor, which
revealjs's htmlFormatExtras also inherits, so one pass covers both.
…14655)

Verified against real axe-core 4.10 in a browser: the html fixture (numbered
code, no other violation source) now reports zero axe-core violations, and
the revealjs fixture's report has no violation targeting a code line-number
anchor (only the pre-existing, unrelated slide-menu-button/viewport-meta
violations remain, tracked separately).
@posit-snyk-bot

posit-snyk-bot commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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.

a11y: code-line-numbers emits per-line links with no accessible name

2 participants