Component
Tooltip and popover
A short label on hover or focus, and a small panel opened by a button.
Plain-text source, for agents and clipboard use: /components/source/tooltip.txt
When to use it
A tooltip names an icon-only control or adds a few words about it, on hover and on focus. A popover is a small panel anchored to its button, for a short task that should not leave the page: a confirmation with one choice, a quick setting. Both sit in the top layer, so no scroll container clips them, and both are placed beside their trigger by the script.
Examples
Tooltips on icon-only buttons
The tooltip is the button’s name, so the button references it with aria-labelledby.
<button class="flux-button flux-button--ghost flux-button--sm" type="button" aria-labelledby="tip-export" data-flux-tooltip="tip-export"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2.5v7.5M5 7l3 3 3-3M3 12.5h10" /></svg></button>
<span class="flux-tooltip" id="tip-export" role="tooltip" popover="manual">Export as CSV</span>
<button class="flux-button flux-button--ghost flux-button--sm" type="button" aria-labelledby="tip-print" data-flux-tooltip="tip-print"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.5 6V2.5h7V6M4.5 11h-2V6h11v5h-2M4.5 9h7v4.5h-7z" /></svg></button>
<span class="flux-tooltip" id="tip-print" role="tooltip" popover="manual">Print manifest</span>Popover
A short confirmation anchored to its button. Light dismiss, Escape and returning focus come from the platform.
Hold 4 seats?
The seats are held for 48 hours, then released to sale.
<button class="flux-button flux-button--secondary" type="button" popovertarget="pop-hold" aria-haspopup="dialog" aria-expanded="false">Hold seats</button>
<div class="flux-popover" id="pop-hold" popover role="dialog" aria-labelledby="pop-hold-title">
<h3 class="flux-popover__title" id="pop-hold-title">Hold 4 seats?</h3>
<p class="flux-popover__body">The seats are held for 48 hours, then released to sale.</p>
<div class="flux-popover__actions">
<button class="flux-button flux-button--ghost flux-button--sm" type="button" popovertarget="pop-hold" popovertargetaction="hide">Cancel</button>
<button class="flux-button flux-button--sm" type="button">Hold seats</button>
</div>
</div>Anatomy
| Part | Description |
|---|---|
| Tooltip | A manual popover with role="tooltip": text-inverse on surface-inverse, one line where possible. |
| Trigger | A focusable control with data-flux-tooltip naming the tooltip’s id. |
| Popover | A panel on surface-raised with a hairline and --flux-popover-shadow, opened with popovertarget. |
| Popover parts | An optional title, a body in text-secondary, and actions aligned to the end. |
API
| Name | Kind | Description |
|---|---|---|
flux-tooltip | class | On an element with role="tooltip", an id and popover="manual". |
data-flux-tooltip | attribute | On the trigger: the tooltip’s id. Opens it on hover and focus. Requires flux-components.js. |
aria-labelledby / aria-describedby | attribute | labelledby when the tooltip is the control’s name, describedby when it adds to a visible label. |
flux-popover | class | On an element with popover, an id and role="dialog", opened by a button with popovertarget. |
flux-popover__title | class | Optional heading, referenced by aria-labelledby. |
flux-popover__body | class | The text of the popover. |
flux-popover__actions | class | Buttons, end-aligned. popovertargetaction="hide" closes without script. |
States
| State | Treatment |
|---|---|
| Tooltip open | Above the trigger, or below when there is no room; stays open while the pointer is over it. |
| Popover open | Below the trigger, aligned to its end, flipped above when there is no room. aria-expanded follows. |
Keyboard
| Keys | Action |
|---|---|
Tab | Focusing a trigger opens its tooltip; leaving it closes it. |
Enter / Space | Opens or closes a popover. Focus moves to its first control. |
Escape | Closes the tooltip or the popover; a popover returns focus to its button. |
Accessibility
- A tooltip opens on focus as well as hover, stays while the pointer is over it, and closes on Escape, as WCAG 1.4.13 requires.
- A tooltip holds text only. Anything interactive belongs in a popover.
- An icon-only button takes its name from its tooltip with aria-labelledby, so the name exists even when the tooltip is closed.
- Give a popover role="dialog" and a name, and keep it short enough that its controls are reached with a few Tabs.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-tooltip-bg | -text | -radius | -font-size | -padding-x | -padding-y | -max-width | -offset
- --flux-popover-width | -padding | -gap | -bg | -border | -shadow | -radius
Do and don’t
Do
- Keep a tooltip to a few words: what the control does.
- Use a popover for one decision about the thing its button is on.
Don’t
- Do not put the only copy of important information in a tooltip. It is invisible until someone looks for it.
- Do not open a popover on hover.
- Do not stack a popover on a popover.