Tooltip
Overlaysimport { Tooltip } from "bits-ui" Shared provider
One Provider supplies a 250ms delay and non-hoverable content policy to a toolbar
<script lang="ts">
import { Tooltip } from 'bits-ui';
import { Bell, Search, Settings2 } from '@lucide/svelte';
const actions = [
{ label: 'Search', shortcut: '⌘K', icon: Search },
{ label: 'Notifications', shortcut: '⌘I', icon: Bell },
{ label: 'Settings', shortcut: '⌘,', icon: Settings2 }
];
</script>
<Tooltip.Provider delayDuration={250} disableHoverableContent={true}>
<div class="card mx-auto flex w-fit items-center gap-1 p-2">
{#each actions as action}
<Tooltip.Root>
<Tooltip.Trigger class="btn btn-ghost size-10 p-0" aria-label={action.label}>
<action.icon class="size-4" />
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="bottom"
sideOffset={8}
class="panel animate-pop-in z-[100] flex items-center gap-3 px-3 py-2 text-xs text-ink-50 shadow-xl"
>
<span>{action.label}</span>
<kbd class="rounded border border-ink-700 bg-ink-900 px-1.5 py-0.5 font-mono text-[10px] text-ink-400">
{action.shortcut}
</kbd>
<Tooltip.Arrow class="fill-ink-800" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
{/each}
</div>
</Tooltip.Provider>
Keyboard focus
Focusable triggers reveal the same descriptions without requiring hover
Press Tab until either control is focused. No pointer is required.
<script lang="ts">
import { Tooltip } from 'bits-ui';
import { Keyboard } from '@lucide/svelte';
</script>
<Tooltip.Provider delayDuration={0} disableHoverableContent={true}>
<div class="mx-auto max-w-md text-center">
<p class="mb-4 text-sm text-ink-400">Press Tab until either control is focused. No pointer is required.</p>
<div class="flex items-center justify-center gap-3">
<Tooltip.Root ignoreNonKeyboardFocus>
<Tooltip.Trigger class="btn btn-primary">
<Keyboard class="size-4" />
Keyboard shortcuts
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="top"
sideOffset={9}
class="panel animate-pop-in z-[100] max-w-56 px-3 py-2 text-left text-xs leading-5 text-ink-200 shadow-xl"
>
Open the command guide. Shortcut: <kbd class="font-mono text-brand-400">?</kbd>
<Tooltip.Arrow class="fill-ink-800" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
<Tooltip.Root ignoreNonKeyboardFocus>
<Tooltip.Trigger class="btn btn-ghost">View activity</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="top"
sideOffset={9}
class="panel animate-pop-in z-[100] px-3 py-2 text-xs text-ink-200 shadow-xl"
>
Shows the last 30 workspace events
<Tooltip.Arrow class="fill-ink-800" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</div>
</div>
</Tooltip.Provider>
Tooltip.Provider is required above every root. Its delayDuration and disableHoverableContent defaults flow to all nested
tooltips, and it ensures only one tooltip in that provider is open. A Tooltip.Portal renders content into document.body by default, avoiding
clipped toolbars and local stacking contexts.
A tooltip does not move or trap keyboard focus; focus stays on its trigger, so its content must be
descriptive rather than an interactive mini-dialog. Escape or an outside pointer-down closes the
content by default, and pressing the trigger with any pointer button also closes it. Use ignoreNonKeyboardFocus when focus caused by a pointer should not open the tooltip; data-state distinguishes delayed, instant, and closed states for animation.