Tooltip

A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.

Installation

Terminal
ReactTailwind
TSX
npx @uiblox/cli add tooltip

Visual Variations

Toggle between three different visual styles: dark (default), light (bordered), and colored (accent).

Basic text tooltip

Includes pointer arrow

Multi-line content

Basic Usage

Copy & paste ready
import { Tooltip } from "@/components/ui";

<Tooltip content="This is a tooltip">
  <Button variant="outline">Hover me</Button>
</Tooltip>

Positions

ReactTailwind CSSCopy & paste ready
<Tooltip content="Top tooltip" side="top">
  <Button variant="outline">Top</Button>
</Tooltip>
<Tooltip content="Right tooltip" side="right">
  <Button variant="outline">Right</Button>
</Tooltip>
<Tooltip content="Bottom tooltip" side="bottom">
  <Button variant="outline">Bottom</Button>
</Tooltip>
<Tooltip content="Left tooltip" side="left">
  <Button variant="outline">Left</Button>
</Tooltip>

With Icons

ReactTailwind CSSCopy & paste ready
<Tooltip content="Edit item">
  <Button size="icon" variant="ghost">
    <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
    </svg>
  </Button>
</Tooltip>

Props

PropTypeDefaultDescription
children*React.ReactNode-The element that triggers the tooltip
content*React.ReactNode-The content to display in the tooltip
side"top" | "right" | "bottom" | "left""top"The side where the tooltip appears
delayDurationnumber200Delay in ms before showing the tooltip

Source Code

Copy this code into src/components/ui/tooltip.tsx:

tooltip.tsx
ReactTailwind
TSX
"use client";

import * as React from "react";
import { cn } from "@/lib/utils";

interface TooltipProps {
  children: React.ReactNode;
  content: React.ReactNode;
  side?: "top" | "right" | "bottom" | "left";
  align?: "start" | "center" | "end";
  delayDuration?: number;
  className?: string;
}

const Tooltip = ({
  children,
  content,
  side = "top",
  align = "center",
  delayDuration = 200,
  className,
}: TooltipProps) => {
  const [visible, setVisible] = React.useState(false);
  const timeoutRef = React.useRef<NodeJS.Timeout>();

  const showTooltip = () => {
    timeoutRef.current = setTimeout(() => setVisible(true), delayDuration);
  };

  const hideTooltip = () => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    setVisible(false);
  };

  const sideClasses = {
    top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
    right: "left-full top-1/2 -translate-y-1/2 ml-2",
    bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
    left: "right-full top-1/2 -translate-y-1/2 mr-2",
  };

  return (
    <div
      className="relative inline-block"
      onMouseEnter={showTooltip}
      onMouseLeave={hideTooltip}
      onFocus={showTooltip}
      onBlur={hideTooltip}
    >
      {children}
      {visible && (
        <div
          role="tooltip"
          className={cn(
            "absolute z-50 px-3 py-1.5 text-sm text-white bg-gray-900 rounded-md shadow-md whitespace-nowrap",
            sideClasses[side],
            className
          )}
        >
          {content}
        </div>
      )}
    </div>
  );
};

export { Tooltip };