Building a tooltip with the popover API


A CSS-only tooltip (without the popover API)

You might be familiar with an old and well-known “CSS trick” for CSS-only tooltips:

<button class="tooltip" data-tooltip="Italic">I</button>
.tooltip:hover::after {
    content: attr(data-tooltip);
    position: absolute;
}

A more accessible version would look something like:

<button aria-labelledby="italics-label">I</button>
<div role="tooltip" id="italics-label">Italic</div>
[role="tooltip"] {
  display: none;
}

button:hover + [role="tooltip"],  
button:focus + [role="tooltip"] {  
  display: block;
}

(Above code courtesy of Inclusive Components.)

For either approach, anchor positioning can be used to position the tooltip in relation to the button.

Some interaction patterns can’t yet be achieved using only HTML and CSS. The following example looks at using JavaScript and the popover API.

A toggletip using the Popover API

Definitions are hazy, but the term toggletip is sometimes used to describe a UI element that, while similar to a tooltip, isn’t only visible while a user is hovering, and is dismissed with a user action.

The following example makes use of anchor positioning and popover="hint" so currently only works in Chrome Canary.

A popover can contain buttons, links, and other interactive content. This example recreates a UI pattern from GitHub.com: a link that shows a card with some additional information on hover. In my reinterpretation, the card is shown on hover or focus, and closed via the escape key or clicking outside the card.

hover-me
Oliver Williams

CSS. Design. UX. UI. Web.

<a href="https://github.com/o-t-w">hover-me</a>

<div popover="hint">
<!-- contents of the popover -->
</div>

The popovertarget attribute can only be used on a button, and only works on click. Calling the .showPopover() method in JavaScript offers more flexibility.

const link = document.querySelector("a");
const popover = document.querySelector("[popover]");

link.addEventListener("mouseover", function() {
popover.showPopover();
});

link.addEventListener("focus", function() {
popover.showPopover();
});

Along with the mouseover event to open the popover on hover, it also listens for the focus event to cater to people using a keyboard to navigate.

When using a button with a popovertarget attribute (or a command and commandfor attribute), the button automatically becomes the anchor of the popover. That’s a useful default behaviour you miss out on when using JavaScript — unless you specify a source element. An object with a source property can be passed as an argument to the .showPopover() method. This avoids the need to set an anchor-name and position-anchor property in CSS.

Let’s improve the previous code:

const link = document.querySelector("a");
const popover = document.querySelector("[popover]");

link.addEventListener("mouseover", function() {
popover.showPopover({ source: this });
});

link.addEventListener("focus", function() {
popover.showPopover({ source: this });
});

The source property is used to specify the DOM node that opened the popover. Using the above code, the link will become the anchor of the popover.

The previous code opens the popover, but what about closing it? Popovers have light-dismiss functionality built-in. The popover will close when the user clicks elsewhere or presses the escape key.

This UI pattern works well on a desktop or laptop but on a phone or tablet the user can only click the link, not bring up the card. The functionality is complementary and non-essential, so that’s acceptable. Users can achieve the actions in the card (follow and sponsor) on the next page after clicking the link.

popover="hint"

The markup for the previous example used popover="hint":

<div popover="hint">
<!-- contents of the popover -->
</div>

I could have used popover="auto" and things would have worked much the same. The key difference is that an "auto" popover will close other popovers, whether you open it with a mouse click, a keyboard button press, or with JavaScript. popover="hint" is primarily designed for hover interactions, and will not close other popovers (unless its opened with a mouse press, which isn’t what its designed for).

Open hint popover
Oliver Williams

CSS. Design. UX. UI. Web.

An "auto" popover

Conclusion

We live in a mobile-first age, but work-related apps are still primarily used on desktop and laptop, and for complex applications without the space to label every button, tooltips still come in handy.