Components

Tooltip

Contextual help revealed on hover or focus. Small dark pill with an arrow pointing at the trigger. Never place critical information here — it must be discoverable.

Updated Jul 16, 2026 by Leonardo Posada

Anatomy

  1. 1
    Trigger

    Any focusable element. Pass asChild so the tooltip wraps YOUR element instead of adding its own.

  2. 2
    Content

    The dark pill: bg-foreground, text-background, text-xs, rounded-md, shadow-sm, sideOffset 6.

  3. 3
    Arrow

    Small triangle (10×5) pointing at the trigger, filled with the same foreground token. Included by default in TooltipContent.

  4. 4
    Provider

    Global context that controls delayDuration + skipDelayDuration. Mount once at layout root (already done in this kit).

Sides

Set side="top" | "right" | "bottom" | "left" on TooltipContent. Default is 'top'. The arrow follows the side automatically — always points at the trigger. Radix auto-flips to the opposite side if there isn't enough room.

<Tooltip>
  <TooltipTrigger asChild><Button variant="outline">Top</Button></TooltipTrigger>
  <TooltipContent side="top">Hint on top</TooltipContent>
</Tooltip>

With and without arrow

The arrow is on by default and is the Yuno default for most tooltips (a small triangle points at the trigger). Pass arrow={false} for compact toolbars or dense zones where the arrow would feel noisy.

With arrow (default)
<Tooltip>
  <TooltipTrigger asChild><Button variant="outline">Hover me</Button></TooltipTrigger>
  <TooltipContent>Create new rule</TooltipContent>
</Tooltip>
Without arrow
<Tooltip>
  <TooltipTrigger asChild><Button variant="outline">Hover me</Button></TooltipTrigger>
  <TooltipContent arrow={false}>Compact toolbar hint</TooltipContent>
</Tooltip>

Delay

delayDuration on <TooltipProvider> (or per-<Tooltip>) controls how long the user hovers before the tooltip opens. Default in the kit: 200ms. Use 0 for critical hints, 700ms for casual ones.

<TooltipProvider delayDuration={0}>
  <Tooltip>
    <TooltipTrigger asChild><Button variant="outline">Instant</Button></TooltipTrigger>
    <TooltipContent>Opens immediately</TooltipContent>
  </Tooltip>
</TooltipProvider>

<TooltipProvider delayDuration={700}>
  <Tooltip>
    <TooltipTrigger asChild><Button variant="outline">Slow</Button></TooltipTrigger>
    <TooltipContent>Opens after 700ms</TooltipContent>
  </Tooltip>
</TooltipProvider>

Length limits

Yuno tooltips are short. Ideal: under 40 characters (a single line). OK: up to ~350 characters (about 5 wrapped lines). Anything longer belongs in a Popover. The kit caps content width at max-w-sm (384px) so long strings wrap into multiple lines instead of stretching horizontally.

Ideal (under 40 chars)
<TooltipContent>Create new rule</TooltipContent>
OK (wraps up to 5 lines at max-w-xs)
<TooltipContent>
  Blocks payments over $500 USD from countries flagged as high-risk in the last 30 days.
  Applies only to card and wallet payment methods.
</TooltipContent>
Too long? Use Popover
If your content needs more than 5 wrapped lines, links, headers or actions, switch to a Popover.
TooltipProvider is already mounted
This kit's layout already wraps everything in <TooltipProvider> so you can drop <Tooltip> anywhere. In your own project, mount it once at the root layout — never nest providers.

Recipes

Ready-to-copy compositions covering the most common Yuno usages of this atom.

Icon-only button hint

The most common Yuno usage: expose the meaning of an icon-only button. Always paired with aria-label on the button.

<Tooltip>
  <TooltipTrigger asChild>
    <button type="button" aria-label="Actions"
      className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-transparent bg-transparent text-muted-foreground transition-all hover:border-border hover:bg-background hover:text-foreground hover:shadow-xs data-[state=open]:border-border data-[state=open]:bg-background data-[state=open]:text-foreground">
      <DotsThreeOutline weight="fill" className="size-4" />
    </button>
  </TooltipTrigger>
  <TooltipContent>Actions</TooltipContent>
</Tooltip>
Disabled input hint

Explain why a field is disabled. Because a disabled Input can't receive hover events, the Tooltip wraps a small parent span that stays hoverable.

<Tooltip>
  <TooltipTrigger asChild>
    {/* Wrap the disabled Input in a span so hover still fires */}
    <span tabIndex={0}>
      <Input placeholder="Managed by admin" disabled />
    </span>
  </TooltipTrigger>
  <TooltipContent>Ask an admin to unlock this field.</TooltipContent>
</Tooltip>
Truncated label reveal

Reveal the full text of a truncated label (table cell, chip). The trigger is the truncated span itself.

Very long rule name that gets truncated in the table cell
<Tooltip>
  <TooltipTrigger asChild>
    <span className="block max-w-40 truncate text-sm">
      Very long rule name that gets truncated in the table cell
    </span>
  </TooltipTrigger>
  <TooltipContent>
    Very long rule name that gets truncated in the table cell
  </TooltipContent>
</Tooltip>

Import

Copy this import line at the top of the file where you compose this atom.

TooltipProvider is already mounted at layout root — you rarely need to import it again.
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";

Props

Everything else from the underlying HTML or Radix primitive is forwarded via ...props.

PropTypeDefaultDescription
Tooltip.delayDurationnumberprovider (200)Per-tooltip override for how long to hover before opening (ms).
Tooltip.open / defaultOpenbooleanControlled or uncontrolled open state. Rare — usually hover-driven.
TooltipTrigger.asChildbooleanfalseMerges props onto the child element (Radix Slot). Always pass asChild when wrapping a real element (Button, span, native button).
TooltipContent.side"top" | "right" | "bottom" | "left""top"Preferred side. Radix auto-flips if there's no room. The arrow follows the side automatically.
TooltipContent.sideOffsetnumber6Distance in px between the trigger and the content.
TooltipContent.arrowbooleantrueShow the small triangle pointing at the trigger. Turn off for compact toolbars or dense zones.
TooltipContent.classNamestringMerged with base classes via cn(). Base includes max-w-xs so long strings wrap into 2 lines.
TooltipProvider.delayDurationnumber200 (kit default)Global hover delay before opening. Applies to every Tooltip inside.
TooltipProvider.skipDelayDurationnumber300If the user moves between triggers within this window, the next tooltip opens instantly.

When to use

  • Explain an icon-only button.
  • Give context to a truncated label.
  • Short definitions of technical terms.
  • Explain why a control is disabled.

When not to use

  • Critical info the user must see — must be visible, not hidden.
  • Long content — use Popover.
  • Actionable content (links, buttons) — use Popover or DropdownMenu.
  • Mobile-only prototypes — hover doesn't exist there.

Usage

Do
  • Wrap the app with <TooltipProvider> once at layout level.
  • Keep tooltip text under 8 words.
  • Always pair icon-only buttons with a tooltip AND aria-label.
  • For disabled triggers, wrap them in a hoverable <span> so the tooltip still opens.
Don't
  • Don't put actionable elements (links, buttons, forms) inside a Tooltip.
  • Don't use Tooltip on touch-only surfaces — hover doesn't exist.
  • Don't hide information the user would need to complete a task.

Related

Cross-links to atoms and patterns you may reach for next.

  • PopoverFor longer content or when the user needs to interact with what's inside.
  • Hover cardFor richer preview content (avatars, previews) with a bigger surface.
  • Dropdown menuWhen the hover reveal should offer actions, not just info.