Tooltip
A short hint shown on hover and keyboard focus, anchored to its trigger in the top layer with hover intent.
Last updated
Uses JavaScript
Opens the bubble in the top layer with hover intent (120 ms on first hover,
instant for neighbours), opens on focus at once, closes on Escape, ignores
touch pointers, and moves aria-describedby onto the focusable trigger.
Without JS: A CSS-only bubble above the trigger on hover and focus; no delay, and an overflow ancestor can clip it.
Show codeHide code
<Tooltip text="Copy to clipboard">
<Button variant="outline" color="neutral">Copy</Button>
</Tooltip>Add
npx @ava-ui/apogee add tooltip
Depends on utils (anchored-panel helper, island). No icons.
Usage
---
import Tooltip from '@/components/apogee/Tooltip/Tooltip.astro'
import Button from '@/components/apogee/Button/Button.astro'
---
<Tooltip text="Copy to clipboard" placement="bottom">
<Button variant="outline" color="neutral">Copy</Button>
</Tooltip>
Anatomy
- Trigger — whatever you put in the default slot. Make it focusable (a
button or link) so keyboard users get the hint too; the island moves
aria-describedbyonto it. - Bubble — a
role="tooltip"popover="manual"span anchored to the trigger, in the top layer.
API
@composable — exposed to Content Editors in AVA. Any other attribute passes
through to the root wrapper <span>.
| Prop | Type | Default | Description |
|---|---|---|---|
text |
string |
— | The hint. Wraps at 20rem. An empty string renders the slot alone, no bubble. |
description |
string |
— | A second, muted line under the text; the bubble becomes left-aligned with more padding. |
arrow |
boolean |
false |
A small triangle on the edge facing the trigger. |
delay |
number |
120 |
Hover delay before opening, in ms. |
closeDelay |
number |
150 |
Delay before closing after the pointer leaves, in ms. |
placement |
'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'start' | 'start-top' | 'start-bottom' | 'end' | 'end-top' | 'end-bottom' |
'top' |
Side and alignment; flips when out of room. start/end mirror in RTL. |
panelClass |
string |
— | Extra classes on the bubble. |
class |
string |
— | Extra classes on the root wrapper. |
Slots: the default slot is the trigger; shortcut renders inline after the text (a Kbd).
Variants
Show codeHide code
<Tooltip text="Edit"><Button variant="ghost" color="neutral" iconOnly aria-label="Edit">✎</Button></Tooltip>
<Tooltip text="Delete"><Button color="critical">Delete</Button></Tooltip>
<Tooltip text="Opens in a new tab"><a href="#" class="text-primary underline">Docs</a></Tooltip>
<Tooltip text="Newest first by default"><Select aria-label="Sort"><option>Newest</option><option>Oldest</option></Select></Tooltip>Description, arrow and shortcut
Show codeHide code
<Tooltip text="Save draft" description="Keeps the draft on this device until you publish.">
<Button variant="outline" color="neutral">Save</Button>
</Tooltip>
<Tooltip text="Bold" arrow><Button variant="outline" color="neutral">B</Button></Tooltip>
<Tooltip text="Search"><Kbd slot="shortcut">⌘K</Kbd><Button variant="outline" color="neutral">Search</Button></Tooltip>
<Tooltip text="Instant" delay={0}><Button variant="outline" color="neutral">No delay</Button></Tooltip>Placement
All twelve values.
Show codeHide code
<Tooltip text="top-start" placement="top-start"><Button variant="outline" color="neutral">top-start</Button></Tooltip>
… one per value …With an existing description
The island appends the bubble’s id to any aria-describedby the trigger
already has, so a control keeps its other descriptions.
Deletes the draft; this cannot be undone.
Delete draftShow codeHide code
<p id="tt-note">Deletes the draft; this cannot be undone.</p>
<Tooltip text="Delete draft">
<Button color="critical" iconOnly aria-label="Delete" aria-describedby="tt-note">✕</Button>
</Tooltip>Long text and clipping
Text wraps at 20rem. The bubble is in the top layer, so an overflow: hidden
ancestor cannot cut it off.
Show codeHide code
<div class="w-56 overflow-hidden rounded-md border border-neutral p-4">
<Tooltip text="Exports every row that matches the current filters as a comma-separated file, including hidden columns.">
<Button variant="outline" color="neutral">Export</Button>
</Tooltip>
</div>States
- Hidden (default) — the popover is closed.
- Shown — after
delay(120 ms) of hover (instantly when a neighbouring tooltip closed within the last 500 ms), or at once on focus; fades in and slides from the trigger’s side (--duration-fast,--ease-standard). - Closing —
closeDelay(150 ms) after the pointer leaves, at once on blur or Escape.
Examples
An icon-only button is the classic case: the visible label is the tooltip,
the accessible name is aria-label.
<Tooltip text="Settings">
<Button variant="ghost" color="neutral" iconOnly aria-label="Settings"><Settings /></Button>
</Tooltip>
Accessibility
| Key | Action |
|---|---|
Tab |
Focusing the trigger shows the tooltip; moving focus away hides it. |
Esc |
Hides the tooltip without moving focus (WCAG 1.4.13). |
- The bubble has
role="tooltip"; the focusable trigger points at it witharia-describedby, so screen readers read the hint after the trigger’s name (hidden popover content still counts as a description). - Appears on keyboard focus, not only hover. Put a focusable element in the slot or keyboard users never see it.
- The hint is supplementary. Never put the only label of a control in a tooltip; give the control an accessible name of its own.
- On touch, a tap shows it; it closes after 4 seconds or on a tap elsewhere.
- The fade respects
prefers-reduced-motion.
Tokens
| Token | Used for |
|---|---|
--background-inverted |
Bubble background |
--on-inverted |
Bubble text |
--radius-md |
Corner radius |
--duration-fast / --ease-standard |
Fade transition |
Do / Don’t
- Do use it for a two-to-five-word hint on icon buttons and truncated labels.
- Do keep the trigger focusable.
- Don’t put links, buttons or formatted text in it; the bubble is plain text and cannot be hovered.
- Don’t rely on it on touch screens; use visible text or a Popover for anything essential.
Content
- Sentence case, no ending period: “Copy to clipboard”, not “Copy to clipboard.”
- Name the action or the outcome, not the control: “Opens in a new tab” rather than “Link”.