Composite

Tooltip

Tooltip exposes the low-level built-in primitives plus a SimpleTooltip convenience wrapper for the common single-trigger case.

Installation

npx shadcn add https://rck.vibeboxph.com//r/tooltip.json

Live preview & controls

Controls
<SimpleTooltip content="Helpful supplementary text">
  <Button variant="outline">Hover for details</Button>
</SimpleTooltip>

Anatomy

  • TooltipProviderShares delay timings across a tree of tooltips.
  • TooltipThe root, holds open state.
  • TooltipTriggerThe element that opens the tooltip on hover/focus.
  • TooltipContentThe floating panel with an arrow.

Props

PropTypeDefaultDescription
content (SimpleTooltip)*React.ReactNodeTooltip body.
placement"top" | "right" | "bottom" | "left"topPreferred placement, flips automatically if there's no room.
delayDurationnumber200Hover delay in ms before opening.
open / onOpenChangeboolean / (open: boolean) => voidControlled open state (for click-triggered tooltips).

Accessibility

  • Opens on both hover and keyboard focus, and closes on Escape — never hover-only.
  • Uses `role="tooltip"` and is associated to the trigger through `aria-describedby`.
  • Content should stay to short, supplementary text — it's not a substitute for visible labels.

Source

registry/rck/ui/tooltip.tsx
"use client";

import * as React from "react";
import * as TooltipPrimitive from "@/registry/rck/primitives/tooltip";
import { cn } from "@/lib/utils";

export const TooltipProvider = TooltipPrimitive.Provider;
export const Tooltip = TooltipPrimitive.Root;
export const TooltipTrigger = TooltipPrimitive.Trigger;

export const TooltipContent = React.forwardRef<
  React.ElementRef<typeof TooltipPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 6, children, ...props }, ref) => (
  <TooltipPrimitive.Content
    ref={ref}
    data-slot="tooltip-content"
    sideOffset={sideOffset}
    className={cn(
      "group bg-foreground text-background z-50 max-w-64 rounded-md px-2.5 py-1.5 text-xs shadow-md",
      "data-[state=delayed-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
      "data-[state=delayed-open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=delayed-open]:zoom-in-95",
      className,
    )}
    {...props}
  >
    {children}
    <TooltipPrimitive.Arrow
      aria-hidden="true"
      className={cn(
        "fill-foreground absolute",
        "group-data-[side=top]:-bottom-1 group-data-[side=top]:left-1/2 group-data-[side=top]:-translate-x-1/2",
        "group-data-[side=bottom]:-top-1 group-data-[side=bottom]:left-1/2 group-data-[side=bottom]:-translate-x-1/2 group-data-[side=bottom]:rotate-180",
        "group-data-[side=right]:top-1/2 group-data-[side=right]:-left-1 group-data-[side=right]:-translate-y-1/2 group-data-[side=right]:rotate-90",
        "group-data-[side=left]:top-1/2 group-data-[side=left]:-right-1 group-data-[side=left]:-translate-y-1/2 group-data-[side=left]:-rotate-90",
      )}
    />
  </TooltipPrimitive.Content>
));
TooltipContent.displayName = "TooltipContent";

/**
 * Convenience wrapper for the common case: a single trigger with plain-text
 * or simple-node content. Use the primitives above directly for full control
 * (custom delays per tooltip, rich interactive content, etc).
 */
export interface SimpleTooltipProps extends Omit<
  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,
  "content"
> {
  content: React.ReactNode;
  children: React.ReactElement;
  delayDuration?: number;
  defaultOpen?: boolean;
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
}

export function SimpleTooltip({
  content,
  children,
  delayDuration = 200,
  defaultOpen,
  open,
  onOpenChange,
  ...contentProps
}: SimpleTooltipProps) {
  return (
    <TooltipProvider delayDuration={delayDuration}>
      <Tooltip defaultOpen={defaultOpen} open={open} onOpenChange={onOpenChange}>
        <TooltipTrigger asChild>{children}</TooltipTrigger>
        <TooltipContent {...contentProps}>{content}</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Related examples

Browse the full examples gallery