caliper uidocs

Tooltip

Free

A short hint that appears on hover or focus, never the only way to learn something.

Installs components/ui/tooltip.tsxDepends on @radix-ui/react-tooltipMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/tooltip.json

The first tooltip waits 300 ms; sweep along and the next ones appear at once.

When to use #

Use it for

  • Naming an icon-only button.
  • Showing a keyboard shortcut or a short clarification.

Skip it when

  • The text is long or interactive; use a popover or hover card.
  • Touch-only contexts where hover does not exist.

Decisions #

Why it is built this way, so you know what to keep when you change your copy.

Behaviour

The first waits, neighbours follow at once
The first tooltip waits 300ms; moving along a toolbar shows the next immediately for half a second, so scanning icons does not mean waiting at each one.
The label cannot be hovered
Tooltip content ignores the pointer, so moving across a toolbar switches labels instead of getting stuck on the last one.

Usage

Never the only explanation
Touch screens have no hover. Anything people need to complete a task belongs on the page, not in a tooltip.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/tooltip.json

Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above. It is built from Tooltip, TooltipTrigger, TooltipProvider and TooltipContent.

example.tsx
import { Bell, FileText, Inbox, Upload } from "lucide-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup } from "@/components/ui/button-group"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"

export function IconTooltip() {
  const tools = [
    { label: "Duplicate", shortcut: "⌘D", icon: <FileText aria-hidden="true" /> },
    { label: "Download PDF", shortcut: "⌘⇧S", icon: <Upload aria-hidden="true" className="rotate-180" /> },
    { label: "Send to customer", shortcut: "⌘↵", icon: <Inbox aria-hidden="true" /> },
    { label: "Notifications", shortcut: "⌘N", icon: <Bell aria-hidden="true" /> },
  ];
  return (
    <TooltipProvider>
      <div className="grid justify-items-center gap-3 pt-10">
        <ButtonGroup aria-label="Invoice tools">
          {tools.map((tool) => (
            <Tooltip key={tool.label}>
              <TooltipTrigger asChild>
                <Button variant="secondary" size="icon" aria-label={tool.label} aria-keyshortcuts={tool.shortcut}>{tool.icon}</Button>
              </TooltipTrigger>
              <TooltipContent shortcut={tool.shortcut}>{tool.label}</TooltipContent>
            </Tooltip>
          ))}
        </ButtonGroup>
        <p className="text-xs text-muted-foreground">The first tooltip waits 300 ms; sweep along and the next ones appear at once.</p>
      </div>
    </TooltipProvider>
  );
}

API reference #

Tooltip

component

No props of its own; it accepts the native props of its root element.

TooltipTrigger

component

No props of its own; it accepts the native props of its root element.

TooltipProvider

component

No props of its own; it accepts the native props of its root element.

TooltipContent

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
shortcutstring—Keyboard shortcut shown after the label, e.g. "⌘D".

Accessibility #

It is built on native elements, so roles and focus come from the browser.

Keyboard and focus handling comes from Radix tooltip: arrow keys move through items, Enter and Space select, and Escape closes and returns focus.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.