Wuko
Components

Tooltip

A short, hover- or focus-revealed label built on Radix Tooltip. Uncontrolled: Radix manages open/close internally; consumers pass content (the body) and children (the trigger). Each Tooltip is self-contained with its own Provider, so no app-root wrap is needed.

Installation

terminal
npx shadcn@latest add @wuko/tooltip

Usage

Wrap any focusable trigger element with a Tooltip. The first row below shows tooltips on Buttons (default top side); the second row demonstrates all four side options.

components/button-row.tsx
import { Bell, Trash2, Zap } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Tooltip } from "@/components/ui/tooltip";

export function ButtonRow() {
  return (
    <div className="flex flex-wrap items-center gap-4">
      <Tooltip content="Trigger a deploy">
        <Button>
          <Zap className="size-4" />
          Deploy
        </Button>
      </Tooltip>
      <Tooltip content="3 unread notifications">
        <Button variant="outline">
          <Bell className="size-4" />
          Inbox
        </Button>
      </Tooltip>
      <Tooltip content="Permanently delete">
        <Button variant="danger">
          <Trash2 className="size-4" />
          Delete
        </Button>
      </Tooltip>
    </div>
  );
}

Props

PropTypeDefaultDescription
contentReactNodeRequired. The tooltip body: a label, hint, or short description of the trigger.
childrenReactNodeRequired. The trigger element. Tooltip uses Radix's asChild pattern, so the trigger renders as your element directly (no extra wrapper).
side"top" | "bottom" | "left" | "right""top"Which side of the trigger to position the tooltip on. Radix automatically flips to the opposite side if the chosen side would cause viewport collision.
sideOffsetnumber8Pixel gap between the trigger and the tooltip. Default 8 matches a typical small-but-distinct visual separation.
delayDurationnumber700Milliseconds before the tooltip opens on hover. Lower values feel more responsive; higher values reduce noise. Each Tooltip has its own Provider, so this delay is per-tooltip.
classNamestringTailwind classes merged onto the tooltip Content (the body, not the trigger).
...restComponentPropsWithoutRef<typeof Tooltip.Content>Forwarded to the underlying Radix Tooltip.Content: id, aria-label, data-*, onEscapeKeyDown, onPointerDownOutside, etc. Excludes children (which we use as the trigger), side, sideOffset, and asChild.