motif svelteArc

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.

Live specimen

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.

Installation

pnpm dlx shadcn-svelte@latest add @arcui/tooltip

Usage

<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

PropTypeDefaultDescription
contentstring | Snippet—Tooltip content. Strings and numbers crossfade and resize when changed.
childrenSnippet<[{ 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

KeyAction
TabFocusing the trigger element opens the tooltip.
EscapeCloses 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