Docs
Tooltip

Tooltip

Displays a positionable Tooltip component.

Its Above Me!

Installation

Install the following dependencies:

npm install class-variance-authority

Copy and paste the following code into your component.

"use client";
import React, { useState, createContext, useContext } from "react";
import { cva, type VariantProps } from "class-variance-authority";
import styles from "./tooltip.module.css";

interface TooltipContextValue {
  isVisible: boolean;
  setVisible: (visible: boolean) => void;
}

const TooltipContext = createContext<TooltipContextValue | undefined>(
  undefined
);

interface TooltipContainerProps {
  children: React.ReactNode;
}

const Tooltip: React.FC<TooltipContainerProps> = ({ children }) => {
  const [isVisible, setVisible] = useState(false);

  const contextValue: TooltipContextValue = {
    isVisible,
    setVisible,
  };

  return (
    <TooltipContext.Provider value={contextValue}>
      <div className={styles.tooltipBase}>{children}</div>
    </TooltipContext.Provider>
  );
};

const useTooltip = () => {
  const context = useContext(TooltipContext);
  if (!context) {
    throw new Error("useTooltip must be used within a Tooltip");
  }
  return context;
};

/* -------------------------------------------------------------------------------------------------
 * TOOLTIP TRIGGER
 * -----------------------------------------------------------------------------------------------*/

const TRIGGER_NAME = "TooltipTrigger";

interface TooltipTriggerProps extends React.HTMLAttributes<HTMLDivElement> {
  children: React.ReactNode;
  className?: string;
}

const TooltipTrigger = React.forwardRef<HTMLDivElement, TooltipTriggerProps>(
  ({ children, className, ...props }, ref) => {
    const { setVisible } = useTooltip();

    const handleMouseEnter = () => {
      setVisible(true);
    };

    const handleMouseLeave = () => {
      setVisible(false);
    };

    return (
      <div
        className={className}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        ref={ref}
        {...props}>
        {children}
      </div>
    );
  }
);

TooltipTrigger.displayName = TRIGGER_NAME;

/* -------------------------------------------------------------------------------------------------
 * TOOLTIP CONTENT
 * -----------------------------------------------------------------------------------------------*/

const CONTENT_NAME = "TooltipContent";

const tooltipVariants = cva(styles.tooltipContent, {
  variants: {
    position: {
      top: styles.top,
      bottom: styles.bottom,
    },
  },
  defaultVariants: {
    position: "top",
  },
});

interface TooltipContentProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof tooltipVariants> {
  children: React.ReactNode;
  className?: string;
}

const TooltipContent = React.forwardRef<HTMLDivElement, TooltipContentProps>(
  ({ children, className, position, ...props }, ref) => {
    const { isVisible } = useTooltip();

    return (
      <div
        className={tooltipVariants({ position, className })}
        id='tooltip-content'
        role='tooltip'
        ref={ref}
        style={{ opacity: isVisible ? "1" : "0" }}
        {...props}>
        {children}
      </div>
    );
  }
);

TooltipContent.displayName = CONTENT_NAME;

export { Tooltip, TooltipTrigger, TooltipContent };

Copy and paste the following CSS into a .module.css file.

.tooltipBase {
  position: relative;
  display: inline-block;
}

.tooltipContent {
  background: hsl(var(--background));
  border-radius: var(--radius);
  border: 1px solid hsl(var(--border));
  color: hsl(var(--foreground));
  font-size: var(--text-sm);
  padding-inline: 0.75rem;
  padding-block: 0.375rem;
  position: absolute;
  top: calc(0% - 40px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  z-index: 50;
  pointer-events: none;
  transition: 0.2s ease-in-out all;
  top: 0%;
}

.top {
  top: calc(0% - 40px);
}

.bottom {
  top: calc(100% + 8px);
}

Update the import paths to match your project setup.

Usage

import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/registry/ui/tooltip/tooltip";
<Tooltip>
  <TooltipTrigger>Its Above Me!</TooltipTrigger>
  <TooltipContent>
    <p>Heyyo, I'm a tooltip!</p>
  </TooltipContent>
</Tooltip>

Examples

Top

Its Above Me!

Bottom

Its Below Me!