Tooltip
A popup that displays contextual information when an element is hovered or focused.
Areia’s Tooltip is built on @data-slot/tooltip and rendered as an Ilha island when you use Tooltip. It handles hover/focus interactions, warm-up behavior between nearby tooltips, collision-aware positioning, Escape dismissal, and accessible tooltip attributes.
import { ilha } from "ilha";
import { Plus } from "lucide";
import { Button, Icon, Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip content="Create project">
<Button
shape="square"
icon={<Icon icon={Plus} />}
aria-label="Create project"
/>
</Tooltip>
));Import
import { Tooltip } from "areia";
Usage
Call Tooltip(...) for an interactive island. The root renders the tooltip markup and initializes the @data-slot/tooltip controller after mount.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip content="Helpful contextual information">
<Button>Hover me</Button>
</Tooltip>
));For static server-rendered markup or custom initialization, use Tooltip.Static(...). For most application usage, call Tooltip(...).
Examples
Basic Tooltip
Use content for the popup and children for the trigger content.
import { ilha } from "ilha";
import { Info } from "lucide";
import { Button, Icon, Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip content="This action cannot be undone.">
<Button
variant="secondary"
shape="square"
icon={<Icon icon={Info} />}
aria-label="More information"
/>
</Tooltip>
));Text Trigger
When the trigger is not an action, render it as a span.
import { ilha } from "ilha";
import { Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip
triggerAs="span"
triggerClass="underline decoration-dotted underline-offset-4"
content="Areia is a vanilla TypeScript component library."
>
Areia
</Tooltip>
));Multiple Tooltips
Tooltips share @data-slot/tooltip warm-up behavior automatically. After one tooltip closes, hovering another tooltip within skipDelayDuration opens it without the normal delay.
import { ilha } from "ilha";
import { Languages, Plus, Settings } from "lucide";
import { Button, Icon, Tooltip } from "areia";
export default ilha.render(() => (
<div class="flex items-center gap-2">
<Tooltip content="Create project">
<Button
shape="square"
icon={<Icon icon={Plus} />}
aria-label="Create project"
/>
</Tooltip>
<Tooltip content="Translate">
<Button
shape="square"
icon={<Icon icon={Languages} />}
aria-label="Translate"
/>
</Tooltip>
<Tooltip content="Settings">
<Button
shape="square"
icon={<Icon icon={Settings} />}
aria-label="Settings"
/>
</Tooltip>
</div>
));Side
Use side to choose the preferred side of the trigger. Collision handling may flip the tooltip at runtime when there is not enough space.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<div class="grid grid-cols-2 gap-3">
<Tooltip side="top" content="Top tooltip">
<Button>Top</Button>
</Tooltip>
<Tooltip side="bottom" content="Bottom tooltip">
<Button>Bottom</Button>
</Tooltip>
<Tooltip side="left" content="Left tooltip">
<Button>Left</Button>
</Tooltip>
<Tooltip side="right" content="Right tooltip">
<Button>Right</Button>
</Tooltip>
</div>
));Alignment
Use align to align the tooltip along the selected side.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<div class="flex items-center gap-3">
<Tooltip align="start" content="Start aligned">
<Button>Start</Button>
</Tooltip>
<Tooltip align="center" content="Center aligned">
<Button>Center</Button>
</Tooltip>
<Tooltip align="end" content="End aligned">
<Button>End</Button>
</Tooltip>
</div>
));Delay Control
Use delay to control how long to wait before opening. Use skipDelayDuration to control the warm-up window after a tooltip closes.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<div class="flex flex-wrap items-center gap-3">
<Tooltip delay={1000} content="Opens after one second">
<Button>1s delay</Button>
</Tooltip>
<Tooltip
delay={0}
skipDelayDuration={0}
content="Opens instantly with no warm-up window"
>
<Button>Instant</Button>
</Tooltip>
</div>
));Without Arrow
Set arrow={false} to hide the decorative arrow.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip arrow={false} content="No arrow">
<Button>Hover me</Button>
</Tooltip>
));Custom Content
The content prop accepts markup.
import { ilha } from "ilha";
import { Button, Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip
content={
<div class="flex max-w-48 flex-col gap-1">
<span class="font-medium">Deploy preview</span>
<span class="text-areia-subtle">
Creates a temporary preview environment.
</span>
</div>
}
>
<Button>Deploy</Button>
</Tooltip>
));Custom Trigger
Use trigger when you need complete control over the trigger markup. The custom trigger must include data-slot="tooltip-trigger".
import { ilha } from "ilha";
import { Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip
content="Custom trigger markup"
trigger={
<span
data-slot="tooltip-trigger"
tabindex="0"
class="inline-flex rounded-full bg-areia-surface-muted px-2 py-1 text-sm text-areia-default"
>
Beta
</span>
}
/>
));Static Composition
Use low-level parts for static markup or when you want to call createTooltip yourself.
import { ilha } from "ilha";
import { Tooltip } from "areia";
export default ilha.render(() => (
<Tooltip.Static
content="Static tooltip markup"
triggerAs="span"
>
Hover me
</Tooltip.Static>
));API Reference
Tooltip
Tooltip is an Ilha island. It accepts standard HTML div attributes plus @data-slot/tooltip options.
| Prop | Type | Default | Description |
|---|---|---|---|
content |
unknown |
- | Content to display inside the tooltip popup. |
children |
unknown |
- | Trigger content when trigger is not provided. |
trigger |
unknown |
- | Custom trigger markup. Must include data-slot="tooltip-trigger". |
triggerAs |
"button" | "span" | "div" | "a" |
"span" |
Tag used for the generated trigger. Defaults to span to avoid nested buttons when wrapping Button(...). |
arrow |
boolean |
true |
Whether to render the decorative arrow. |
class |
string |
- | Additional CSS classes applied to the tooltip root. |
className |
string |
- | Alias for class. |
triggerClass |
string |
- | Additional CSS classes applied to the generated trigger. |
triggerClassName |
string |
- | Alias for triggerClass. |
contentClass |
string |
- | Additional CSS classes applied to the tooltip popup. |
contentClassName |
string |
- | Alias for contentClass. |
side |
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" |
"top" |
Preferred side relative to the trigger. |
align |
"start" | "center" | "end" |
"center" |
Preferred alignment along the selected side. |
sideOffset |
number |
4 |
Distance from the trigger in pixels. |
alignOffset |
number |
0 |
Offset from the aligned edge in pixels. |
avoidCollisions |
boolean |
true |
Flip or shift to stay inside the viewport. |
collisionPadding |
number |
8 |
Viewport edge padding used for collision handling. |
delay |
number |
300 |
Delay before showing the tooltip in milliseconds. |
skipDelayDuration |
number |
300 |
Warm-up window where another tooltip opens without delay. Set 0 to disable. |
portal |
boolean |
true |
Portal content to document.body while open. |
onOpenChange |
(open: boolean) => void |
- | Called when visibility changes. |
Tooltip.Trigger
Generated trigger element.
| Prop | Type | Default | Description |
|---|---|---|---|
as |
"button" | "span" | "div" | "a" |
"span" |
Trigger tag name. |
children |
unknown |
- | Trigger content. |
class |
string |
- | Additional CSS classes. |
className |
string |
- | Alias for class. |
Tooltip.Content
Popup container.
| Prop | Type | Default | Description |
|---|---|---|---|
children |
unknown |
- | Tooltip content. |
arrow |
boolean |
true |
Whether to render Tooltip.Arrow. |
side |
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" |
"top" |
Preferred side styling. |
class |
string |
- | Additional CSS classes. |
className |
string |
- | Alias for class. |
Tooltip.Arrow
Decorative arrow element. The controller positions it with inline top/left values and data-side attributes.
| Prop | Type | Default | Description |
|---|---|---|---|
children |
unknown |
SVG | Custom arrow content. |
class |
string |
- | Additional CSS classes. |
className |
string |
- | Alias for class. |
Accessibility
Behavior
- Opens on pointer hover for mouse/pen input.
- Opens on keyboard focus.
- Touch hover is ignored; touch devices use focus behavior.
- Pressing
Escapehides the tooltip. - Moving from the trigger to the tooltip content keeps it open.
- Disabled triggers do not open tooltips.
ARIA
The controller automatically handles:
role="tooltip"on the popup content.aria-describedbyon the trigger while the tooltip is open.aria-hidden="true"/"false"on the tooltip content.- Stable generated IDs for content when needed.
Trigger Labels
Tooltips are supplemental. Icon-only triggers still need an accessible name, usually with aria-label on the trigger button.