Skip to content

Conversation

@iansan5653
Copy link
Contributor

@iansan5653 iansan5653 commented Mar 25, 2025

KeybindingHint renders the key symbols as aria-hidden spans and the key names as VisuallyHidden spans to provide a good experience for both sighted and screen reader users.

However, there is a bug in Chrome where aria-hidden text is included in a label generated using aria-labelledby. More context from https://github.com/github/accessibility/issues/8018#issuecomment-2751656621:

KeybindingHint (the Primer component we are using under the hood here) does try to account for this by rendering the symbol in an aria-hidden span and rendering the name of that symbol in an sr-only span next to it. However, there seems to be a bug in Chrome where the accessibility tree is incorrectly accounting for aria-hidden text in the target of an aria-labelledby. So we get the following (abridged) HTML:

... Add attachment ( command shift at @ ) This results in an incorrectly calculated accessible label of "Add attachment ( command ⌘ shift ⇧ at @ )".

If the label was being calculated correctly by the browser, we'd get a label of "Add attachment (command shift at)" (which looks wrong at first glance but sounds correct when read aloud by a screen reader - you don't say "command plus shift plus at" out loud).

Ideally we really want to fix this bug in the component so that consumers don't have to manually work around, so the approach used in primer/react#5626 works but it isn't ideal - it relies on consumers doing things correctly.

I don't think the way KeybindingHint itself works can really be improved much. If we were to update it to render the hidden keys and label next to each other, rather than mixed in, it would slightly improve what is being read but the data would still be duplicated. KeybindingHint's approach does work well in cases that don't involve aria-labelledby - when read as part of the document flow the output is correct.

I think the solution probably has to be in IconButton or TooltipV2. KeybindingHint does export a helper function that gives you the plain accessible string representation of a shortcut, so we could build the aria-label string ourselves rather than using aria-labelledby in IconButton. Or, a more robust approach might be to update TooltipV2 to move the id prop into a child element so that the tooltip could better control exactly what makes it into the label; then we could move KeybindingHint outside that element and add an sr-only element inside with just the string representation of the shortcut.

To work around this bug, I've taken the approach proposed in the quote to update TooltipV2 to exclude the keybinding hint from the id-tagged container. Then I added the keybinding hint text as a plain hidden string inside that container.

Before in VoiceOver/Chrome:

VoiceOver text readout reading 'link, Learn More( shift ⇧ question mark ?)

After:

VoiceOver text readout reading 'link, Learn More (shift question mark)

Note this isn't a perfect example because obviously "question mark" is combined with "shift", but it's pulled from storybook so I just kept it. Intuitively you might think the label should be "shift + question mark", but when read by a screen reader this can result in the awkward label "shift plus question mark" - it's better to just exclude the punctuation here.

Changelog

New

Changed

Fixed a Chrome bug impacting accessible labels rendered by TooltipV2 with the keybindingHint prop.

Removed

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Merge checklist

@iansan5653 iansan5653 requested a review from a team as a code owner March 25, 2025 17:28
@iansan5653 iansan5653 requested a review from joshblack March 25, 2025 17:28
@changeset-bot
Copy link

changeset-bot bot commented Mar 25, 2025

🦋 Changeset detected

Latest commit: 6b96334

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Mar 25, 2025
@github-actions
Copy link
Contributor

👋 Hi, this pull request contains changes to the source code that github/github depends on. If you are GitHub staff, we recommend testing these changes with github/github using the integration workflow. Thanks!

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2025

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 105.6 KB (+0.04% 🔺)
packages/react/dist/browser.umd.js 105.94 KB (+0.02% 🔺)

@github-actions github-actions bot requested a deployment to storybook-preview-5818 March 25, 2025 17:32 Abandoned
)
const triggerEl = getByRole('button', {name: 'Heart'})
expect(triggerEl).toHaveAccessibleDescription('Love is all around ( command h )')
expect(triggerEl).toHaveAccessibleDescription('Love is all around (command h)')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This is indicative of the one potential breaking change I see for dotcom - we may need to update some test selectors to remove spaces around the keybinding hint in the labels. This is an intentional change.

@iansan5653 iansan5653 enabled auto-merge (squash) March 27, 2025 14:38
@iansan5653 iansan5653 disabled auto-merge March 28, 2025 14:01
@iansan5653 iansan5653 added this pull request to the merge queue Mar 28, 2025
Merged via the queue into main with commit a19676d Mar 28, 2025
44 checks passed
@iansan5653 iansan5653 deleted the keybindinghint-labelledby-bug branch March 28, 2025 14:15
@primer primer bot mentioned this pull request Mar 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants