For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to documentation URLs. Homepage markdown is available at /llms.md/content.md. An agent skill is available at /.well-known/agent-skills/site-skill.md.

Tooltip

The Tooltip component from this design system, built on Base UI.

Installation

$ pnpm dlx shadcn@latest add @cobalt/tooltip

Defaults

The popup is a small text-only pill: a hairline border, a soft shadow and the popover surface in both themes. It opens below the trigger with a 10px gap and a small arrow, and fades, scales and blurs in and out over 200ms (no motion under reduced-motion). Pass side to place it elsewhere, or showArrow={false} to drop the arrow. For an icon button, use <Button tooltip="Label" /> instead of wiring Tooltip, TooltipTrigger and TooltipContent by hand.

Source

"use client";

import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
import { cn } from "cn";

function TooltipProvider({
  delay = 0,
  ...props
}: TooltipPrimitive.Provider.Props) {
  return (
    <TooltipPrimitive.Provider
      data-slot="tooltip-provider"
      delay={delay}
      {...props}
    />
  );
}

function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
  return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
}

function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
  return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
}

function TooltipContent({
  className,
  side = "bottom",
  sideOffset = 10,
  align = "center",
  alignOffset = 0,
  size = "sm",
  showArrow = true,
  children,
  ...props
}: TooltipPrimitive.Popup.Props &
  Pick<
    TooltipPrimitive.Positioner.Props,
    "align" | "alignOffset" | "side" | "sideOffset"
  > & {
    size?: "sm" | "default";
    showArrow?: boolean;
  }) {
  return (
    <TooltipPrimitive.Portal>
      <TooltipPrimitive.Positioner
        align={align}
        alignOffset={alignOffset}
        side={side}
        sideOffset={sideOffset}
        className="isolate z-50"
      >
        <TooltipPrimitive.Popup
          data-slot="tooltip-content"
          className={cn(
            "pointer-events-none z-50 inline-flex max-w-[240px] items-center gap-1.5 origin-(--transform-origin) rounded-[8px] border border-border bg-popover font-medium text-popover-foreground select-none shadow-[shadow:var(--shadow-dropdown,0_1px_1px_0_rgb(0_0_0/0.04),0_4px_4px_0_rgb(0_0_0/0.02))] transition-[scale,opacity,filter] duration-200 ease-out data-[instant]:transition-none data-starting-style:scale-90 data-starting-style:opacity-0 data-starting-style:blur-[4px] data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:blur-[4px] motion-reduce:transition-none motion-reduce:data-starting-style:scale-100 motion-reduce:data-starting-style:opacity-100 motion-reduce:data-starting-style:blur-none motion-reduce:data-ending-style:scale-100 motion-reduce:data-ending-style:opacity-100 motion-reduce:data-ending-style:blur-none",
            size === "sm"
              ? "px-2.5 py-1.5 text-xs leading-4 tracking-[0.15px]"
              : "rounded-[10px] px-3 py-2 text-sm leading-5 tracking-normal",
            className
          )}
          {...props}
        >
          {showArrow && (
            <TooltipPrimitive.Arrow className="data-[side=top]:-bottom-[6px] data-[side=bottom]:-top-[6px] data-[side=left]:-right-[6px] data-[side=right]:-left-[6px]">
              {(
                [
                  ["top", 12, 7, "M0 0 L6 6 L12 0"],
                  ["bottom", 12, 7, "M0 7 L6 1 L12 7"],
                  ["left", 7, 12, "M0 0 L6 6 L0 12"],
                  ["right", 7, 12, "M7 0 L1 6 L7 12"],
                ] as const
              ).map(([direction, width, height, path]) => (
                <svg
                  key={direction}
                  width={width}
                  height={height}
                  viewBox={`0 0 ${width} ${height}`}
                  className={cn(
                    "hidden overflow-visible fill-popover stroke-border [[data-side=top]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))] [[data-side=bottom]>&]:[filter:drop-shadow(0_-1.5px_1px_rgb(0_0_0/0.05))] [[data-side=left]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))] [[data-side=right]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))]",
                    direction === "top" && "[[data-side=top]>&]:block",
                    direction === "bottom" && "[[data-side=bottom]>&]:block",
                    direction === "left" && "[[data-side=left]>&]:block",
                    direction === "right" && "[[data-side=right]>&]:block"
                  )}
                  aria-hidden="true"
                >
                  <path d={path} />
                </svg>
              ))}
            </TooltipPrimitive.Arrow>
          )}
          {children}
        </TooltipPrimitive.Popup>
      </TooltipPrimitive.Positioner>
    </TooltipPrimitive.Portal>
  );
}

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };