A small, non-interactive label that appears on hover or focus to describe a control. Uses role="tooltip" and wires the trigger to the tooltip via aria-describedby so assistive technologies announce it as a description of the control.
Tooltips are not for interactive content — buttons, links, or forms inside a tooltip will be inaccessible to keyboard users and unreachable by pointer since the tooltip closes on mouseleave. Use Popover for interactive overlays.
Opens after a short hover delay (300ms) or when the trigger receives focus. Dismisses on mouseleave, blur, or ESC.
---
import Tooltip from "../tooltip.astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
---
<div class={stack({ gap: "md", direction: "row", align: "center" })}>
<Tooltip id="astro-demo-tooltip-default" content="Save the document (⌘S)">
<button class={css({ px: "sm", py: "xs" })}>Save</button>
</Tooltip>
</div>Use the placement prop to control where the tooltip appears relative to its trigger. Floating UI flips or shifts automatically to keep the tooltip inside the viewport.
---
import Tooltip from "../tooltip.astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
const placements = ["top", "right", "bottom", "left"] as const;
---
<div class={stack({ gap: "md", direction: "row", align: "center" })}>
{
placements.map((placement) => (
<Tooltip
id={`astro-tt-placement-${placement}`}
content={`Tooltip on ${placement}`}
placement={placement}
>
<button class={css({ px: "sm", py: "xs" })}>{placement}</button>
</Tooltip>
))
}
</div>All tooltips on the page share a single DOM element and a single open-delay timer. The first trigger you hover pays the full openDelay (300ms); hovering a neighbour while a tooltip is open — or within 500ms after it closes — skips the delay and the tooltip slides from the previous trigger’s anchor to the new one (FLIP animation). This matches the macOS toolbar feel and keeps dense UIs feeling snappy without sacrificing the “first hover is deliberate” guarantee.
---
import Tooltip from "../tooltip.astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
const actions = [
{ id: "bold", label: "Bold (⌘B)", icon: "B" },
{ id: "italic", label: "Italic (⌘I)", icon: "I" },
{ id: "underline", label: "Underline (⌘U)", icon: "U" },
{ id: "strike", label: "Strikethrough", icon: "S" },
{ id: "link", label: "Insert link (⌘K)", icon: "🔗" },
];
const buttonClass = css({
px: "sm",
py: "xs",
minWidth: "2.25rem",
borderRadius: "sm",
fontFamily: "mono",
fontSize: "sm",
});
---
<div class={stack({ gap: "2xs", direction: "row", align: "center" })}>
{
actions.map((action) => (
<Tooltip id={`astro-tt-group-${action.id}`} content={action.label}>
<button class={buttonClass} aria-label={action.label}>
{action.icon}
</button>
</Tooltip>
))
}
</div>| prop | type | default | req | description |
|---|---|---|---|---|
| content | stringSnippet | undefined | Tooltip content. Can be a plain string or a Svelte snippet for rich markup. | |
| id | string | auto-generated UUID | Unique identifier used for the tooltip element and wired to the trigger via aria-describedby. | |
| placement | "top""top-start""top-end""bottom""bottom-start""bottom-end""left""left-start""left-end""right""right-start""right-end" | "top" | Preferred placement of the tooltip relative to the trigger. Floating UI flips or shifts as needed. | |
| triggerStrategy | "hover""focus""hover-focus""manual" | "hover-focus" | How the trigger opens the tooltip. 'hover' opens on mouseenter. 'focus' opens on focus. 'hover-focus' combines both (recommended for accessibility). 'manual' leaves event wiring to the consumer. | |
| openDelay | number | 300 | Delay in ms before a hover trigger opens the tooltip. Ignored by focus/manual. | |
| closeDelay | number | 100 | Delay in ms before a hover trigger closes the tooltip. Ignored by focus/manual. | |
| offset | number | 6 | Distance in pixels between trigger and tooltip. | |
| size | "sm""md""lg" | "md" | Visual size variant. | |
| open | boolean | false | Controls the open/closed state. Bindable in Svelte — useful for the 'manual' strategy. | |
| children | Snippet<[{ 'data-tooltip-trigger': true }]> | undefined | Snippet that renders the trigger element. The tooltip wires hover/focus listeners to the node you attach the props to. |