Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility: add aria-label for tooltips #28849

Merged
merged 4 commits into from
Nov 30, 2020
Merged

Accessibility: add aria-label for tooltips #28849

merged 4 commits into from
Nov 30, 2020

Conversation

MattyQ
Copy link
Contributor

@MattyQ MattyQ commented May 30, 2019

Update to tooltip.js and tests to add an aria-label attribute that contains the original title of the element, but only if the element doesn't have an existing, valid aria-label attribute.

This is to address cases where screen readers are not capturing the aria-describedby attribute that is added when the tooltip is triggered. This should also avoid a label not being read because of any race conditions between the screen reader and the appearance of the tooltip.

In the case the aria-describedby attribute is added as intended, it overrides the aria-label, so there should be no collision between the two methods of labeling. The aria-label attribute is added conditionally to avoid conflicting with other ways someone might already be adding aria-label attributes to their elements.

@MattyQ MattyQ requested a review from a team as a code owner May 30, 2019 16:56
@MattyQ MattyQ changed the title Accessibility update for tooltip.js Accessibility: aria-label update for tooltip.js May 30, 2019
@patrickhlauke
Copy link
Member

do you have any more information about situations where aria-describedby isn't actually picked up by AT? and note that aria-describedby does not override aria-label (or at least, it shouldn't), but rather complements it (which, at least in theory, would result in the label, followed by the description, being announced)

@MattyQ
Copy link
Contributor Author

MattyQ commented May 30, 2019

Thanks for catching the aria-describedby bit, Patrick, I was conflating describedby with labelledby.

The key issue I'm seeing is with elements that use a tooltip, have a title, but no AT-readable content, such as links that display a font-rendered icon (like using Font Awesome for links to GitHub, Twitter, etc).

The universal issue is passive reading of these elements. Because bootstrap removes the content of the title attribute, when these elements are read as part of a larger group (like a parent element), the tooltips aren't triggered, and so the aria-describedby attribute isn't added to those elements. They end up being skipped or just read as an element reference because the title attribute is empty and there are no other labels or content present.

I've also run into this when actively giving the elements focus using a screen reader (tested using Orca with Firefox and ChromeVox with Chrome). When the element takes focus, at least in the case of these two screen readers, the state of element is grabbed before the tooltip is triggered, so the aria-describedby attribute is never used.

I think the simplest fix would be to leave the title attribute populated so AT still has that reference. My concern there, though, is disrupting implementations of bootstrap where people expect that title attribute to be empty.

Otherwise, applying an aria-label to the element seemed to make the most sense as it gives a static reference for AT, rather than relying on the dynamic appearance of the tooltip.

However, in the case AT manages to capture both the aria-label and the aria-describedby reference, then that's not really a tenable fix.

js/src/tooltip.js Outdated Show resolved Hide resolved
@Johann-S
Copy link
Member

@patrickhlauke your call here, the code LGTM 👍

@MattyQ
Copy link
Contributor Author

MattyQ commented May 31, 2019

I'm definitely up for tweaking this to find the best solution, just want to make sure that those elements aren't missed.

@patrickhlauke
Copy link
Member

not had a chance to live test, but as a quick note: can't leave the title attribute as is, as that will trigger the browser's default tooltip in addition to the bootstrap tooltip. almost tempted to say that controls that only rely on title for their accessible name are pushing it a bit, as title is generally mapped to the accessible description, rather than accessible name...and it's a bit of a last resort for AT to then announce it in the absence of anything else...

for when i get a chance to look at this properly, do you have a live example / test case of the problem itself, @MattyQ ?

@MattyQ
Copy link
Contributor Author

MattyQ commented May 31, 2019

Yeah, for sure:

  • https://testydocsy.netlify.com -- (where I encountered it) this is an example site for an opensource documentation template that's getting ready for public release. The issue occurs with the icons at the bottom of the page (user mailing list, Twitter, Stack Overflow on the left, GitHub, Slack, and developer mailing list on the right).

  • https://dashboardpack.com/ -- Pulled this from the Bootstrap Expo page. The same issue occurs with the social media icons in the upper-right corner of the page (if you scroll, the header becomes fixed and loses the icons, so only visible when at the top of the page).

  • https://demo.bootstraptor.com/starter-kit-pro/ -- Pulled from looking for sites using bootstrap. Issue occurs with the HTML5, Bootstrap, and Sass logos in the upper-right corner of the page.

The pattern looks to be that the elements have no other AT-readable content. Adding aria-describedby when the tooltip is triggered does work for elements that have content (such as the tooltip examples in the bootstrap doc). If I pull the content out of those examples, my screen readers go back to reporting the element reference only.

Note: I found on the bootstraptor site that when using ChromeVox if I click the icon twice, I picked up the added aria-describedby attribute. I hadn't noticed this on the others, as they're links and there wasn't a chance to click a second time. Interestingly, even if I wait a short while to ensure that the tooltip has loaded on bootstraptor, when I let ChromeVox read it, it still doesn't get the description until the second time I trigger a click.

However, when using Orca, I was never able to get the description.

@MattyQ
Copy link
Contributor Author

MattyQ commented May 31, 2019

Not sure if one of these approaches might be better? In general, I want to defer to your experience, Patrick.

  • Handle it in the documentation. We could document for now that this is a behavior of tooltips when applied to an element that doesn't have any AT-readable content. I'm not sure how much support it has, but it sounds like aria-details would be a better attribute to use in this case? When it's viable, we could then apply that on the element that triggers the tooltip instead of aria-describedby, though aria-describedby still fits the spec better, I think.

  • I believe most AT will skip reading elements that are set to display: none, but it looks like my screen readers will still pull them as a description if they're explicitly referenced using aria-describedby. I think it's probably among the messiest approaches, but we could create a hidden element that stays in the DOM and serves as the description for the triggering element, rather than relying on the ephemeral tooltips.

@MattyQ
Copy link
Contributor Author

MattyQ commented Jun 13, 2019

Updated the code and tests to not apply aria-label attributes to elements that otherwise have readable content.

@patrickhlauke
Copy link
Member

sorry for taking so long. will review later today. still feel a bit uneasy about this being an overly-aggressive intervention for something authors should think about, but can also see why it wouldn't even occur to authors that it may be a problem since we do magic swapping around of attributes on the element anyway. might need an extra small note in the docs to warn about this automagic behavior too...will have a think. but yes, conceptually it sounds like a fair approach. wonder if this will catch more complex situations like an SVG with a <title> or other similar scenarios (i.e. if that would pass or fail the text content check)...

@MattyQ
Copy link
Contributor Author

MattyQ commented Jun 25, 2019

No apologies necessary, and I can appreciate the concern. In my testing I found textContent did pick up the title element of an SVG, but it's a good question about other complex situations. I know it's a lot of back and forth to end up not using the code, but I think it makes sense that if this may be too hamfisted (I'd rather not introduce more problems to solve a small one), we could retire this pull request and look at trying to solve why AT is missing the aria-describedby on triggered, text-empty elements.

I guess that leaves the issue where elements that are read passively won't return clear content, but that could be handled in the doc with guidance not to rely on tooltips for the only readable content of an element.

@Johann-S
Copy link
Member

Hey @MattyQ, I removed QUnit and switch to Jasmine, so now your unit tests should go there: https://github.com/twbs/bootstrap/blob/master/js/src/tooltip/tooltip.spec.js

js/tests/unit/tooltip.js have been removed, so if you need any help do not hesitate 😉

@patrickhlauke
Copy link
Member

sorry, it's my fault for not looking at this in a more timely fashion...i'll look at this more thoroughly and change up the jira tests etc

@MattyQ
Copy link
Contributor Author

MattyQ commented Jul 29, 2019

My bad this time for being off the grid -- I'll get those tests updated!

@mdo mdo changed the base branch from master to main June 16, 2020 20:18
@XhmikosR
Copy link
Member

@patrickhlauke how do you want to proceed with this? If we want this to land, we'd need to rebase it and migrate it to the new test framework. Also, I'm unsure if we want this backported.

@XhmikosR
Copy link
Member

@patrickhlauke friendly ping :)

Copy link
Member

@patrickhlauke patrickhlauke left a comment

Choose a reason for hiding this comment

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

beyond the tweak to the if statement, I think this makes sense. sorry for the delay and reviewing, this fell off my radar (and, well ... 2020)

js/src/tooltip.js Outdated Show resolved Hide resolved
@patrickhlauke
Copy link
Member

@XhmikosR @Johann-S i'm lost with the new test framework ... any clues how the old QUnit tests here can be ported? it seems a lot of the old tests aren't even run anymore either

@XhmikosR
Copy link
Member

@patrickhlauke let me understand this patch first; it only adds an aria-label attribute to the original element if those 3 requirements are true, right? It doesn't affect the tooltip at all?

@XhmikosR
Copy link
Member

I pushed a patch but I don't know if the place or the method I used are right. I basically create a tooltip in each test and check for the original element's attributes.

I'd wait until @Johann-S or someone else can help us

Copy link
Member

@Johann-S Johann-S left a comment

Choose a reason for hiding this comment

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

You don't need to show the tooltip and it LGTM after that 👍

done()
})

tooltip.show()
Copy link
Member

Choose a reason for hiding this comment

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

it's not needed to show the tooltip this part of the code is executed after the constructor

done()
})

tooltip.show()
Copy link
Member

Choose a reason for hiding this comment

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

same here

done()
})

tooltip.show()
Copy link
Member

Choose a reason for hiding this comment

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

same here

@XhmikosR
Copy link
Member

@Johann-S feel free to make any further changes otherwise let's merge it as is.

@Johann-S
Copy link
Member

after the last requested changes it'll be good to go

@XhmikosR
Copy link
Member

XhmikosR commented Nov 16, 2020 via email

js/src/tooltip.js Outdated Show resolved Hide resolved
MattyQ and others added 4 commits November 30, 2020 11:37
Update to the tooltip.js to add an aria-label attribute that contains the original title of the element, but only if the element doesn't have an existing aria-label attribute.

This is to address cases where screen readers are not capturing the aria-describedby attribute that is added when the tooltip is triggered.  This should also avoid a race condition between the screen reader and the appearance of the tooltip.
@XhmikosR XhmikosR dismissed Johann-S’s stale review November 30, 2020 10:07

This works; any further tweaks could land later

@XhmikosR XhmikosR merged commit 03ed3e0 into twbs:main Nov 30, 2020
@XhmikosR XhmikosR changed the title Accessibility: aria-label update for tooltip.js Accessibility: add aria-label for tooltips Nov 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants