Tooltip ported
Short supporting text for unfamiliar controls.
A short label on hover or focus that opens without delay when moving between tooltips, with collision flipping and spring sizing.
Loading demo…
Guidance
When to use
- One-line labels on icon-only buttons in toolbars.
- Revealing the full text of truncated labels on hover or focus.
- Dense toolbars where moving between icons should show labels instantly after the first one.
When not to use
- Use Popover for anything with links or controls inside.
- Use Hover Card for rich previews such as a person or link.
- Avoid it for information people must see on touch devices, where hover does not exist.
pnpm dlx shadcn-svelte@latest add @arcui/tooltipUsage
<script lang="ts">
import Tooltip from '$lib/components/tooltip/tooltip.svelte';
import Archive from '@lucide/svelte/icons/archive';
</script>
<Tooltip content="Archive project">
{#snippet children({ props })}
<button {...props} type="button" aria-label="Archive project">
<Archive size={16} />
</button>
{/snippet}
</Tooltip>Variants & Examples
Top Placement
Default placement anchored above the trigger element.
<Tooltip content="Duplicate item" side="top">
{#snippet children({ props })}
<button {...props} type="button" aria-label="Duplicate"><Copy size={16} /></button>
{/snippet}
</Tooltip>Bottom Placement
Anchored below the trigger, ideal for upper navigation bars.
<Tooltip content="Account settings" side="bottom">
{#snippet children({ props })}
<button {...props} type="button" aria-label="Settings"><Settings size={16} /></button>
{/snippet}
</Tooltip>Custom Snippet Content
Renders custom rich markup snippet within the tooltip bubble.
{#snippet tip()}
<span>Keyboard shortcut: <strong>⌘S</strong></span>
{/snippet}
<Tooltip content={tip}>
{#snippet children({ props })}
<button {...props} type="button">Save</button>
{/snippet}
</Tooltip>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
content | string | Snippet | — | Tooltip content. Strings and numbers crossfade and resize when changed. |
children | Snippet<[{ props }]> | — | Your trigger element as a snippet: spread the received props onto your own button. Focus opens the tooltip and Escape closes it. |
side | 'top' | 'bottom' | 'top' | Preferred side of the trigger element. |
Keyboard Interactions
| Key | Action |
|---|---|
Tab | Focusing the trigger element opens the tooltip. |
Escape | Closes the tooltip immediately. |
Accessibility
- Bits UI links the content to the trigger with aria-describedby and renders role="tooltip".
- Content is supplemental: icon-only triggers still need their own aria-label.
- Do not put interactive elements inside; use Popover instead.
Motion
Phase 1 still-state: hover opens after 250ms, keyboard focus opens instantly, both with a 3px rise from 0.97 scale and static string rendering. Phase 2 springs bubble width and height to content changes with motionTokens.spring.morph. Reduced motion drops transforms and keeps a 90ms opacity fade.
Notes for AI
- Use for one-line labels on icon buttons and truncated text. Use Hover Card for rich previews and Popover for interactive controls.
- Each Tooltip brings its own provider; no app-level wrapper is needed. Pass your button in the children snippet (with the props argument) and spread its props — the button itself becomes the trigger, so focus and aria-describedby land on it.
Source of truth: registry/components/tooltip/tooltip.tsx