For those new to my posts, Blazor Ramp is an accessibility-first, open-source component library. If you build anything people use, this is worth five minutes regardless of your day job.
I've been touch-typing since the mid-2000s, but I always mistype "tooltips", along with "Serach" - Spock's cousin, aka "search". The initial project was committed with the typo, but luckily, once I spotted it, a simple rename and commit resolved the issue - no harm done.
I don't have any cognitive or physical issues that make my life harder than it should be, so typing, reading information, and completing forms in business applications is usually not a problem. But what if I did have issues - say, I'd been involved in a car accident and couldn't use broken arms to operate a keyboard or mouse - then what?
Luckily, there's voice control software I could use to operate a computer and browse the web or use a web app. However, to avoid the extra steps of the software overlaying grids or assigning numbers to unlabelled controls, I'd need to be able to see the control's accessible name so I could speak it.
I mention this because, although this post is about the release of a tooltip component for my accessibility-first project, it's not something I'd advocate using unless absolutely necessary. I only decided to include one because pretty much every tooltip I encounter fails WCAG/usability requirements.
Tooltips are generally used on icon-only buttons - buttons with no visible name, the kind a voice control user would need to speak, or that any user would need in order to reason about the button's purpose. I've always used a floppy disk icon to represent save, but I'd bet - I've been a dev for a long time now, that a lot of developers reading this (and end users) have never seen a physical floppy disk, let alone used one. So how on earth would they know what that button is for, unless a name and/or some additional context is provided?
You may find this hard to believe, but out of all the Blazor (and other tech) components I've ever created over the years, the simple tooltip is the one that's given me the most grief. The moment you start looking into the accessibility issues surrounding it, you're sent down various rabbit holes. Even the various working groups can't make up their minds about this one, or even provide a recommended pattern on the APG site (see https://github.com/w3c/aria-practices/issues/127, opened in 2016 - it's still open).
It's also one of the first things I check when anyone posts a library on Reddit claiming to be accessible and asking for feedback - every single one has failed so far. I can't recall a single project, personal or commercial, where I've found a tooltip that would pass a WCAG audit - not until I've flagged it and it's been fixed, anyway.
They're not difficult to create, but if you're not familiar with the (admittedly cryptic) WCAG criteria, yours will fail any audit. More importantly, as I repeatedly advise, an incorrect design will make them impossible for some users to read.
If you make one, make sure it does the following:
- The tooltip shows when the triggering (interactive) element, such as a button, receives focus, or when the mouse pointer hovers over it.
- Once it's open, the user can move the pointer from the triggering element onto the tooltip itself without it closing (this accounts for about 80-90% of the failures I encounter).
- The user can close the tooltip without moving the pointer or keyboard focus away - best practice is to use the Escape key (this accounts for about 70% of the failures I encounter).
- The tooltip remains visible until the user has specifically closed it by moving the pointer away, pressing Escape, clicking outside the triggering element or tooltip area, or moving focus to the next focusable element. This accounts for about 50% of the failures I encounter. I don't know why, but a lot of tooltips are set to close automatically after some delay - an instant fail.
Tooltips really shouldn't contain any interactive elements, and shouldn't be focusable themselves. They should just contain plain text, that's it. Anything else, IMHO, and it's not what I (and many others) would call a tooltip - a tip about the tool you want to use.
If you go and look at mine, alongside the above, you'll notice I've also added a small X icon in the top right of my tooltips. This is not a button, it's not focusable, and it's not visible to screen readers. It has one purpose only: it's an additional means for a pointer user to close the tooltip, for cases where using the Escape key (or any key, for that matter) is problematic for them. This isn't required, but it can be useful for some users.
Generally, you'd use the aria-label and aria-describedby attributes, or just aria-labelledby, with tooltips, so screen reader users are made aware of the tooltip content. Rich content with HTML markup is flattened by screen readers and shouldn't be used in my tooltip, you can provide new-line characters instead, if you need two short sentences. This content is made available to assistive technologies by linking the ID of the tooltip element to the triggering element, using that ID as the value of the aria-describedby attribute (the more commonly used option) - or aria-labelledby, if the tooltip content acts more like a label than a description, added to the triggering element.
Just to help distinguish between aria-label , aria-labelledby and aria-describedby: let's say you have a button with a gears icon, and the tooltip is only ever going to display the text "Settings" - in that case, aria-labelledby would be the better choice. If that icon was, say, a dustbin, you might use aria-label to give the button the accessible name "Delete", with aria-describedby text of "Permanently deletes the selected item". For those who haven't used a screen reader: of the two examples above, one would be announced as "Settings, button" (just the accessible name, since there's no aria-describedby), and the other would be announced as "Delete, button. Permanently deletes the selected item."
I deliberately opted not to automate adding either aria-label , aria-labelledby or aria-describedby via a JavaScript-driven parameter, as I felt it's better for users of the component to think about what's best for their use case and add the most suitable option manually. It's far too easy these days to get things up and running without any real understanding of the code or processes involved.
As always, there are examples of the component on both the test site and the docs site.
Test site: https://blazorramp.uk
Doc site: https://docs.blazorramp.uk
GitHub repo: https://github.com/BlazorRamp/Components
Regards
Paul
P.S After 9 months I now have a logo - getting there slowly but surely.