Fylgja Tooltip
A tooltip is a short text hint tied to a control, shown when the reader hovers or
focuses it. It is built from three native platform features: a popover="hint"
element for the text, the interestfor attribute on the trigger to open it, and CSS
anchor positioning to place it next to the trigger. The browser handles the hover
delay, keyboard focus, Escape to close, and the description link for assistive
technology, so there is no JavaScript involved.
Use a tooltip only for supplementary text, like a keyboard shortcut or a longer explanation of a short label. Never put essential information in it: touch users rarely see it, and some readers never hover at all.
Preview
Hover the button or move focus to it with the keyboard.
<button type="button" interestfor="save-hint">Save draft</button>
<div id="save-hint" popover="hint">Shortcut: Ctrl + S</div>
<style>
[popover="hint"] {
margin: 0.5rem;
inset: auto;
position-area: var(--tooltip-position, block-start);
position-try-fallbacks: flip-block, flip-inline;
max-inline-size: 16rem;
padding: 0.25rem 0.5rem;
border: 0;
border-radius: 0.375rem;
background-color: var(--root-fg);
color: var(--root-bg);
font-size: 0.875rem;
}
</style>Usage
- Give the tooltip an
idandpopover="hint". A hint popover sits in the top layer, and opening it does not close other open popovers, such as a menu the trigger lives in. - Point the trigger’s
interestforattribute at thatid. The browser shows the tooltip after a short hover or on keyboard focus, and hides it when interest ends or the reader presses Escape. - Add the small
<style>rule. It resets the default popover placement and usesposition-areato place the tooltip above the trigger.interestformakes the trigger the tooltip’s implicit anchor, so noanchor-nameis needed.
position-try-fallbacks flips the tooltip to the other side when there is no room,
for example at the top of the viewport. The colors invert --root-bg and --root-fg,
so the tooltip follows light and dark mode.
Anatomy
| Part | Responsibility |
|---|---|
Trigger with interestfor |
Opens the tooltip on hover or focus and becomes its anchor. |
[popover="hint"] |
The tooltip text, rendered in the top layer while shown. |
position-area |
Places the tooltip on a side of the trigger, above by default. |
--tooltip-position |
Optional override for that side, set on the tooltip itself. |
Accessibility
- While the tooltip is shown,
interestforexposes its text as the trigger’s description, the same relationshiparia-describedbycreates. Do not addaria-describedbyyourself. - Keyboard users get the tooltip on focus, and Escape hides it without moving focus.
- On touch screens the browser shows it on a long press, where supported. Many touch users will still never see it, which is why it must stay optional.
- Keep the text short and plain. No links, buttons, or form controls inside, since the tooltip closes as soon as interest moves away from the trigger.
- Use a focusable trigger, such as a
<button>or a link. A tooltip on a plain<span>cannot be reached with the keyboard.
Variants
Placement
Set --tooltip-position on the tooltip to any position-area value, such as
block-end (below) or inline-end (after the trigger). The fallbacks still flip it
when it would overflow.
<button type="button" interestfor="archive-hint">Archive</button>
<div id="archive-hint" popover="hint" style="--tooltip-position: block-end">Moves the item out of your inbox</div>
<button type="button" interestfor="snooze-hint">Snooze</button>
<div id="snooze-hint" popover="hint" style="--tooltip-position: inline-end">Brings it back tomorrow morning</div>Icon button
An Icon Button has no visible text, so a tooltip with
its name helps sighted mouse and keyboard users. The tooltip is not the name,
though: keep the aria-label on the button, so it stays named when the tooltip is
closed or interestfor is not supported. Keep the <svg> as the only child, so
the button stays square.
<button type="button" interestfor="copy-hint" aria-label="Copy link">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
</button>
<div id="copy-hint" popover="hint">Copy link</div>Browser support
Each of the three features ships on its own timeline, so check Can I use before relying on them.
interestforis the newest piece and is available in Chromium based browsers first. Where it is missing, the trigger works as normal and the tooltip simply never opens.popover="hint"falls back to a manual popover in browsers that do not know the hint value, which still works with the script below.- Anchor positioning is needed for the placement. Without it the tooltip opens at the edge of the viewport instead of next to its trigger.
Because a tooltip only carries extra information, letting it stay hidden is an
acceptable fallback. When you do want it everywhere, add this script once per page.
It only runs where interestfor is missing, opens the tooltip on hover and focus,
and links the description with aria-describedby.
<script>
if (!("interestForElement" in HTMLButtonElement.prototype)) {
for (const trigger of document.querySelectorAll("[interestfor]")) {
const tooltip = document.getElementById(trigger.getAttribute("interestfor"));
if (!tooltip) continue;
// Without interestfor there is no implicit anchor, so name one per pair.
const anchor = `--${tooltip.id}`;
trigger.style.anchorName = anchor;
tooltip.style.positionAnchor = anchor;
trigger.setAttribute("aria-describedby", tooltip.id);
const show = () => tooltip.togglePopover(true);
const hide = () => tooltip.togglePopover(false);
trigger.addEventListener("pointerenter", show);
trigger.addEventListener("pointerleave", hide);
trigger.addEventListener("focus", show);
trigger.addEventListener("blur", hide);
trigger.addEventListener("keydown", (event) => {
if (event.key === "Escape") hide();
});
}
}
</script>
Related: Speed Dial, Modal.
FAQ
Why not use the title attribute?
A title tooltip only appears on mouse hover, never on keyboard focus or touch, cannot be styled, and is announced inconsistently by screen readers. A hint popover opened with interestfor shows on hover and focus, closes with Escape, and is linked to its trigger as a description.
Can I put a link or a button inside a tooltip?
No. A tooltip disappears as soon as the pointer or focus leaves the trigger, so nobody can reliably reach anything inside it. When the content needs to be interactive, open a regular popover on click with command="toggle-popover" instead.
How do I change how fast the tooltip appears?
Set the interest-delay property on the trigger. It takes a delay for showing and one for hiding, such as interest-delay 0.2s 0.5s. The browser default leaves a short pause so tooltips do not flash while the pointer crosses the page.
Why does nothing appear in my browser?
interestfor is still new and not available in every engine yet. Without it the tooltip stays hidden and the trigger keeps working as a plain button. Add the small fallback script from the Browser support section if the hint matters to you.