nextcloud-vue
nextcloud-vue copied to clipboard
[BITV/A11Y] Tooltips accessibility
- [ ] TODO: update nextcloud-vue in server: https://github.com/nextcloud/server/pull/33387
- [ ] check if requirements are met
- [ ] Need to be focusable and accessible via keyboard.
- [ ] Need to be possible to close via the Escape key.
- [ ] Needs to be possible to move the mouse over the tooltip, currently it disappears. This is an issue when zooming and panning.
- [ ] Make sure all tooltips look and work in a consistent manner
- [x] Take care of delaying all tooltips, https://github.com/nextcloud/nextcloud-vue/issues/2216
note: we are using a third party library which might be outdated
Useful links to implement accessible tooltips:
- https://sarahmhigley.com/writing/tooltips-in-wcag-21/
- https://www.youtube.com/watch?v=lb0_v7D4kbs&ab_channel=MSFTEnable
- https://codepen.io/smhigley/pen/KjoerX
Some of tooltips are inconsistent: some shows a file name, some show an icon, some of them are reachable via icon only. There are should be done in a same way. See some examples:

in nextcloud-vue 6.0.0 beta there was a move to "floating-vue" which I hope is more accessible: https://github.com/nextcloud/nextcloud-vue/pull/2600
since this is done by Raimund from the community it's not clear if that library satisfies the a11y requirements so we need to verify
now I'm not sure where I got the list of requirements in the original post, especially the idea that it needs to be possible to tab into them. need to recheck with WCAG/BITV for more precise requirements
I've searched for requirements regarding tooltips and here are my points.
What a tooltip have to be / should not be.
3 main conditions for Content on Hover or Focus (AA)
- Dismissable A mechanism is available to dismiss the additional content without moving pointer hover or keyboard focus, unless the additional content communicates an input error or does not obscure or replace other content.
- Hoverable If pointer hover can trigger the additional content, then the pointer can be moved over the additional content without the additional content disappearing
- Persistent The additional content remains visible until the hover or focus trigger is removed, the user dismisses it, or its information is no longer valid.
From https://www.w3.org/WAI/standards-guidelines/wcag/new-in-21/#1413-content-on-hover-or-focus-aa
- Please keep in mind, that information, which is inside of a tooltip sometimes can't be reachable / obvious to use / visible and can't be explored and screen readers sometimes ignore descriptive text by default. It is almost impossible to test all use cases incl/ browsers, screen readers, mobile devices and so on. That means that this information will be lost. Please never put important information inside of the tooltip.
- Tooltip should contain only small peace of additional information.
General requirements
- Tooltips must be discoverable and readable with a mouse, other pointer devices, keyboard, screen reader, zoom software, and any other assistive technology.
- The visual display can be controlled by either a keyboard or a mouse.
- Closing process can be controlled by either a keyboard or a mouse. Using
Esckey is not a best solution.A global escape listener would not be able to differentiate between a user wanting to dismiss a tooltip vs. close a dialog, dropdown menu, if one were open. - Follow a logical tab order.
- Be easy to access without dismissing the tooltip and without relying on fine motor control.
- Only interactive elements have to trigger tooltips. But! Touch devices and other alternative pointers can't reach tooltips on buttons or links (hover is unavailable on a touch device). The reason for it is that button or links triggers there own events and it is not possible to trigger those events and show a tooltips in a same time.
- Tooltip have to never overlap other content. That is a very tricky point especially with combination with magnification software or just ZoomText. Also https://www.w3.org/TR/WCAG21/#resize-text could be a reason for failure.
- Tooltips doesn't have a timeout to hide itself.
- Combining pointer and keyboard events must not create multiple tooltips or other buggy behavior.
- Tooltip must not be dismissed while moving mouse over the tooltip content. Also with combination with magnification software or just ZoomText.
- Tooltp's content must not be lost by using magnification software or just ZoomText.
Implementation requirements
- Do not use the title attribute to create a tooltip.
- Avoid aria-haspopup and aria-live.
- Ensure the tooltip is unreachable when hidden via aria-hidden.
- Use aria-describedby or aria-labelledby to associate the UI control with the tooltip.
- Tooltip have to be opened on focus or mouse over, and closes on blur or mouse out.
- Allow a mouse or pointer user to hide the tooltip through a close button.
- To close a tooltip via keyboard use
Ctr.
Good-looking tooltip (after UX study)

From
- https://www.youtube.com/watch?v=lb0_v7D4kbs&ab_channel=MSFTEnable,
- https://sarahmhigley.com/writing/tooltips-in-wcag-21/#:~:text=The%20accessibility%20requirements%20of%20tooltips,not%20required%20to%20operate%20it,
- https://inclusive-components.design/tooltips-toggletips/
- https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html
Usage of tooltips through our apps
There are several examples regarding usages. Most of them are used for action buttons or links and just some text (sometoes just duplicating text). Some of them are used for "placeholder" inside of input element.

















Conclusion
It is very hard to meet all most important requirements to fulfill accessibility fulfillment. It is also hard to find a very-accessible implementation e.g. third libraries.
As is wrote above, tooltips makes no sense on touch devices and other alternative pointers can't reach tooltips on buttons or links.
I would suggest to move tooltips out and replace important and for user relevant pieces of information with other UI elements and / or place this additional text to hidden elements and bind them via aria-describedby.
@nimishavijay, @jancborchardt i will be happy to hear a feedback from you π§‘
@JuliaKirschenheuter thanks a lot for the research!
I think I observed that in some scenarios we do use "aria-describedby" as soon as a tooltip appears. But the latter only appears whenever the tooltip opens. It disappears when the tooltip closes. Not sure if this is suitable. It might be part of the tooltip implementation.
Before hover:

After hover:

I can't tell if this is sufficient or whether we should go through all tooltips across every app in Hub and try and replace it with an inline text of sorts if the content is essential.
I think I observed that in some scenarios we do use "aria-describedby" as soon as a tooltip appears.
Right connection with element via "aria-describedby" is of coarse an important part of implementation. But besides this 95% work should be done too. For a moment only "aria-describedby" wouldn't help us a lot. (Please look in my general requirements)
I would suggest to move tooltips out and replace important and for user relevant pieces of information with other UI elements and / or place this additional text to hidden elements and bind them via aria-describedby.
I donβt fully understand β is the suggestion to get rid of tooltips? Cause tooltips are useful, also for sighted people. Totally agree with the aria-describedby point, and then using that to show the tooltip text.
Visually, we can use 2 different approaches depending on case, if thatβs ok?
| title (when text is there but could be ellipsized) | tooltip (for showing supporting text) |
|---|---|
![]() |
![]() |
Yes, currently we sometimes show the title for text that could be ellipsized but is not, like if the subline is only short. What can we do here β is having a title so bad? Otherwise we need to figure out via JS if it does overlap, and show the title attribute based on that?
Regarding the requirements, they all make sense to me, except this:
Dismissable A mechanism is available to dismiss the additional content without moving pointer hover or keyboard focus, unless the additional content communicates an input error or does not obscure or replace other content.
Without moving the pointer hover or keyboard focus β so it can not be an x close button like in the example. It has to be something like Esc, no? I would also say that Esc is quite ok for that. We can have a global stack listening for Esc, which first closes any tooltip if open, then a menu if open, then a viewer if open, etc.
Without moving the pointer hover or keyboard focus β so it can not be an x close button like in the example.
Imagine you are on a mobile device. How could you close a tooltip then? What if there are multiple tooltips in several rows like

It has to be something like
Esc, no? I would also say thatEscis quite ok for that. We can have a global stack listening for Esc, which first closes any tooltip if open, then a menu if open, then a viewer if open, etc.
Well, Esc will be listened everywhere. Once Esc is pushed - everything will be closed.
Imagine you are on a mobile device. How could you close a tooltip then? What if there are multiple tooltips in several rows like
On Android system, tooltips vanish when you scroll or tap anywhere (even on tooltip, or on the icon it belongs to). That sounds reasonable? They are initiated via long-press, just for the record.
On Android system, tooltips vanish when you scroll or tap anywhere (even on tooltip, or on the icon it belongs to). That sounds reasonable?
i know, i'm just speaking about accessibility criteria
I've searched for possible solutions what could we "take and integrate" and this seems not good. There are several web components library and almost all of them are not accessible.
Not accessible:
- https://www.webcomponents.org/element/@polymer/paper-tooltip/demo/demo/index.html
- https://design.if.eu/components/overlay/info-tooltip
- https://www.htmlelements.com/demos/tooltip/overview/
- https://googlechromelabs.github.io/howto-components/howto-tooltip/#demo
- https://studio.webcomponents.dev/edit/collection/fO75441E1Q5ZlI0e9pgq/VmbuRedDUMmN4amLK7ie/src/index.ts?p=stories
- https://incubator.app.fi/tooltip-demo/tooltip
- https://vcf-tooltip.netlify.app/
- https://cdpn.io/pen/debug/KjoerX
Probably accessible
- https://overheid.vlaanderen.be/webuniversum/v3/documentation/js-components/vl-ui-tooltip/
Most accessible
- https://carbondesignsystem.com/components/tooltip/accessibility https://carbondesignsystem.com/components/tooltip/usage https://vue.carbondesignsystem.com/?path=/info/components-cvtooltip--default-tootlip
But: https://vue.carbondesignsystem.com/?path=/info/components-cvtooltip--default-tootlip
- is very simple and it state can't be controlled via JS. This one is only done via CSS.
- can't be extended / changed
https://vue.carbondesignsystem.com/?path=/story/components-cvtooltip--default-interactive-tootlip
- can't be extended / changed
Disadvantages of the using of carbondesignsystem:
- Can be used as a whole bundle with all components and styles (we need probably only one)
- Not easy to change / extend
- Each tooltip component (default-interactive-tootlip or default-tootlip) have buttons inside. This makes an integration in our system hard and a wrong result will be reached: our Button will be inside of the button from the library. Regarding semantics and accessibility this i unacceptable.
I'm searching for a possible solution for our own tooltip implementation.
Last status / suggestion: use a native tooltips only like small additional information in combination with other a11y tools like aria-describedby or aria-label's. This should be fine.
For now not to use a custom tooltips because this would take lot's of time and the risk to fail through a11y test is high. As example could be: custom tooltip overlaps other important information by zooming. It's almost impossible to test everything and exclude such cases.
Once we have certification we can think about our own designed and accessible tooltip.
somehow I feel like we'll have to review all tooltips across the platform (at least Nextcloud Hub scope) and for each:
- check if the information is additional: if yes, keep/remove/native
- if the information is not additional but critical:
- revisit the UI design around it to make the additional information accessible in a different way
- maybe: add a button to trigger the extra info and use the Popover component to show more detailed information in a closeable popup (these should be accessible, with close button)
at this point I'm not sure yet how many tooltips would need a full rework
in the server repo (stable25):
- title attribute:
[: \.]+title\s?=: 150+ occurrences (+ a few bogus matches) - v-tooltip: 30 occurrences
might be manageable to go through them to find the essential (non-additional) ones
There may also be occurrences where the title attribute is set in javascript:
rg "'title'" | grep ".js" | grep -v dist | grep -v 3rdparty19 occurences
But might not be complete depending on how that is set
nextcloud-vue:
grep -rie '[: \.]title\s\?=' --exclude=node_modules src | wc -l: ~73 (might include docs/examples)grep -rie 'v-tooltip\s\?=' --exclude=node_modules src | wc -l: 3 (strange, I thought we'd be using v-tooltip everywhere)
Files external know-how - @PVince81 who might be best to talk with Julia about it? Tomorrow afternoon would be perfect, can you find somebody to get in touch with her and have a call about it at that time (Wednesday afternoon).
@artonge ^
Meeting is arranged :)
Thanks a lot! Highly appreciated! π
Added issues for activity and notifications to the list for you @JuliaKirschenheuter by going through https://github.com/nextcloud/server/blob/c16f59379bee79dab9382c90e114c6b34dc07401/core/shipped.json#L3-L50 but if anyone is aware of more then please add them as well :)
done for server

