logo
CtrlK
ComponentsTemplates

Components

Accordion
Alert
Avatar
Badge
Banner
Bottom Navigation
Breadcrumb
Button
Call to Action
Card
Date Picker
Divider
Dropdown
Featues
File Upload
Footer
Header
Hero
Loader
Pagination
Popover
Sidebar
Skeleton
Social Share
Tabs
Testimonial
Tooltip

Pages

Error Pages
Blog List
  1. Docs
  2. Components
  3. Tooltip

Tooltip

Tooltip is a small pop-up box that appears when a user places the mouse pointer over an element.

Basic Tooltip

import React, { useState } from "react";
interface TooltipProps {
  text: string;
  position?: "top" | "right" | "bottom" | "left";
  children: React.ReactNode;
}

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

  return (
    <div className="relative inline-block">
      <div
        onMouseEnter={() => setIsVisible(true)}
        onMouseLeave={() => setIsVisible(false)}
      >
        {children}
      </div>
      <div
        className={`
          absolute z-10 px-3 py-2 text-sm font-medium text-gray-900 bg-white/90 
          rounded-lg shadow-lg border border-gray-200/20
          transition-all duration-300 ease-out
          ${isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-1"}
          bottom-full left-1/2 transform -translate-x-1/2 -translate-y-2
        `}
      >
        {text}
      </div>
    </div>
  );
};

const BasicTooltip = () => {
  return (
    <div className="flex items-center justify-center h-screen bg-gray-100 dark:bg-gray-900">
      <Tooltip text="This is a simple tooltip">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-blue-500 to-blue-600 rounded-lg hover:from-blue-600 hover:to-blue-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Hover me
        </button>
      </Tooltip>
    </div>
  );
};

export default BasicTooltip;

Arrow Tooltip

import React, { useEffect, useRef, useState } from "react";
interface TooltipProps {
  text: string;
  position?: "top" | "right" | "bottom" | "left";
  children: React.ReactNode;
}

const TooltipArrow: React.FC<TooltipProps> = ({
  text,
  position = "top",
  children,
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const tooltipRef = useRef<HTMLDivElement>(null);
  const targetRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const updatePosition = () => {
      if (isVisible && tooltipRef.current && targetRef.current) {
        const targetRect = targetRef.current.getBoundingClientRect();
        const tooltipRect = tooltipRef.current.getBoundingClientRect();
        let top = 0;
        let left = 0;

        switch (position) {
          case "top":
            top = -tooltipRect.height - 10;
            left = (targetRect.width - tooltipRect.width) / 2;
            break;
          case "right":
            top = (targetRect.height - tooltipRect.height) / 2;
            left = targetRect.width + 10;
            break;
          case "bottom":
            top = targetRect.height + 10;
            left = (targetRect.width - tooltipRect.width) / 2;
            break;
          case "left":
            top = (targetRect.height - tooltipRect.height) / 2;
            left = -tooltipRect.width - 10;
            break;
        }

        tooltipRef.current.style.top = `${top}px`;
        tooltipRef.current.style.left = `${left}px`;
      }
    };

    updatePosition();
    window.addEventListener("resize", updatePosition);
    return () => window.removeEventListener("resize", updatePosition);
  }, [isVisible, position]);

  return (
    <div className="relative inline-block">
      <div
        ref={targetRef}
        onMouseEnter={() => setIsVisible(true)}
        onMouseLeave={() => setIsVisible(false)}
      >
        {children}
      </div>
      <div
        ref={tooltipRef}
        className={`
          absolute z-10 px-3 py-2 text-sm font-medium
          text-gray-900 bg-white/90
          rounded-lg shadow-lg border border-gray-200/20
          transition-all duration-300 ease-out
          ${isVisible ? "opacity-100 scale-100" : "opacity-0 scale-95"}
          tooltip-${position}
        `}
        style={{ whiteSpace: "nowrap" }}
      >
        {text}
        <div
          className={`
            absolute w-2 h-2 bg-white/90 border-t border-l border-gray-200/20
            transform rotate-45
            ${
              position === "top"
                ? "bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 -rotate-45"
                : position === "right"
                ? "left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 -rotate-135"
                : position === "bottom"
                ? "top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 rotate-135"
                : "right-0 top-1/2 -translate-y-1/2 translate-x-1/2 rotate-45"
            }
          `}
        />
      </div>
    </div>
  );
};

const ArrowTooltip = () => {
  return (
    <div className="flex items-center justify-center space-x-4 h-64 bg-gray-100 dark:bg-gray-900">
      <TooltipArrow text="Left tooltip" position="left">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-purple-500 to-purple-600 rounded-lg hover:from-purple-600 hover:to-purple-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Left
        </button>
      </TooltipArrow>
      <TooltipArrow text="Top tooltip" position="top">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-blue-500 to-blue-600 rounded-lg hover:from-blue-600 hover:to-blue-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Top
        </button>
      </TooltipArrow>
      <TooltipArrow text="Bottom tooltip" position="bottom">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-red-500 to-red-600 rounded-lg hover:from-red-600 hover:to-red-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Bottom
        </button>
      </TooltipArrow>
      <TooltipArrow text="Right tooltip" position="right">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-green-500 to-green-600 rounded-lg hover:from-green-600 hover:to-green-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Right
        </button>
      </TooltipArrow>
    </div>
  );
};

export default ArrowTooltip;

Animated Tooltip

import React, { useState } from "react";
interface TooltipProps {
  text: string;
  position?: "top" | "right" | "bottom" | "left";
  children: React.ReactNode;
}

const TooltipAnimated: React.FC<TooltipProps> = ({ text, children }) => {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div className="relative inline-block">
      <div
        onMouseEnter={() => setIsVisible(true)}
        onMouseLeave={() => setIsVisible(false)}
      >
        {children}
      </div>
      <div
        className={`
          absolute z-10 px-3 py-2 text-sm font-medium
          text-gray-900 bg-white/90
          rounded-lg shadow-lg border border-gray-200/20
          transition-all duration-500 ease-out
          transform
          ${
            isVisible
              ? "opacity-100 visible translate-y-0 scale-100"
              : "opacity-0 invisible translate-y-1 scale-95"
          }
          bottom-full left-1/2 -translate-x-1/2 -translate-y-2
        `}
      >
        {text}
      </div>
    </div>
  );
};

const AnimatedTooltip = () => {
  return (
    <div className="flex items-center justify-center h-screen bg-gray-100 dark:bg-gray-900">
      <TooltipAnimated text="This tooltip animates smoothly">
        <button className="px-4 py-2 text-white bg-gradient-to-b from-indigo-500 to-indigo-600 rounded-lg hover:from-indigo-600 hover:to-indigo-700 transition-all duration-300 shadow-lg hover:shadow-xl">
          Hover for animated tooltip
        </button>
      </TooltipAnimated>
    </div>
  );
};

export default AnimatedTooltip;

Multi Direction Tooltip

Adaptive tooltip that changes direction based on available space.

import React, { useEffect, useRef, useState } from "react";
interface TooltipProps {
  text: string;
  position?: "top" | "right" | "bottom" | "left";
  children: React.ReactNode;
}

type Direction = "auto" | "top" | "right" | "bottom" | "left";

const TooltipAdaptive: React.FC<TooltipProps & { direction?: Direction }> = ({
  text,
  children,
  direction = "auto",
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const [currentDirection, setCurrentDirection] =
    useState<Direction>(direction);
  const tooltipRef = useRef<HTMLDivElement>(null);
  const targetRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const updatePosition = () => {
      if (
        isVisible &&
        tooltipRef.current &&
        targetRef.current &&
        direction === "auto"
      ) {
        const targetRect = targetRef.current.getBoundingClientRect();
        const tooltipRect = tooltipRef.current.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;

        let newDirection: Direction = "top";

        if (targetRect.top > tooltipRect.height) {
          newDirection = "top";
        } else if (viewportWidth - targetRect.right > tooltipRect.width) {
          newDirection = "right";
        } else if (viewportHeight - targetRect.bottom > tooltipRect.height) {
          newDirection = "bottom";
        } else if (targetRect.left > tooltipRect.width) {
          newDirection = "left";
        }

        setCurrentDirection(newDirection);
      } else {
        setCurrentDirection(direction);
      }
    };

    updatePosition();
    window.addEventListener("resize", updatePosition);
    return () => window.removeEventListener("resize", updatePosition);
  }, [isVisible, direction]);

  const getTooltipStyles = () => {
    switch (currentDirection) {
      case "top":
        return "bottom-full left-1/2 transform -translate-x-1/2 -translate-y-2";
      case "right":
        return "top-1/2 left-full transform translate-x-2 -translate-y-1/2";
      case "bottom":
        return "top-full left-1/2 transform -translate-x-1/2 translate-y-2";
      case "left":
        return "top-1/2 right-full transform -translate-x-2 -translate-y-1/2";
      default:
        return "bottom-full left-1/2 transform -translate-x-1/2 -translate-y-2";
    }
  };

  return (
    <div className="relative inline-block">
      <div
        ref={targetRef}
        onMouseEnter={() => setIsVisible(true)}
        onMouseLeave={() => setIsVisible(false)}
      >
        {children}
      </div>
      <div
        ref={tooltipRef}
        className={`
          absolute z-10 px-3 py-2 text-sm font-medium
          text-gray-900 bg-white/90
          rounded-lg shadow-lg border border-gray-200/20
          transition-all duration-300 ease-out
          ${isVisible ? "opacity-100 scale-100" : "opacity-0 scale-95"}
          ${getTooltipStyles()}
        `}
      >
        {text}
        <div
          className={`
            absolute w-2 h-2 bg-white/90 border-t border-l border-gray-200/20
            transform rotate-45
            ${
              currentDirection === "top"
                ? "bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 -rotate-45"
                : currentDirection === "right"
                ? "left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 -rotate-135"
                : currentDirection === "bottom"
                ? "top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 rotate-135"
                : "right-0 top-1/2 -translate-y-1/2 translate-x-1/2 rotate-45"
            }
          `}
        />
      </div>
    </div>
  );
};

const TooltipDemo = () => {
  const [globalDirection, setGlobalDirection] = useState<Direction>("auto");

  const getTooltipDirection = (defaultDirection: Direction): Direction => {
    return globalDirection === "auto" ? defaultDirection : globalDirection;
  };

  return (
    <div className="flex flex-col items-center justify-center min-h-screen space-y-8 p-4 bg-gray-100 dark:bg-gray-900">
      <div className="flex space-x-2 p-1 bg-gray-200/50 dark:bg-gray-800/50 rounded-lg">
        {["auto", "top", "right", "bottom", "left"].map((dir) => (
          <button
            key={dir}
            onClick={() => setGlobalDirection(dir as Direction)}
            className={`
              px-4 py-2 rounded-md transition-all duration-300
              ${
                globalDirection === dir
                  ? "bg-white text-gray-900 shadow-md"
                  : "text-gray-600 dark:text-gray-300 hover:bg-white/50"
              }
            `}
          >
            {dir.charAt(0).toUpperCase() + dir.slice(1)}
          </button>
        ))}
      </div>
      <div className="grid grid-cols-3 gap-4 w-full max-w-lg">
        <div></div>
        <TooltipAdaptive
          text="Top tooltip"
          direction={getTooltipDirection("top")}
        >
          <button className="w-full px-4 py-2 text-white bg-gradient-to-b from-teal-500 to-teal-600 rounded-lg hover:from-teal-600 hover:to-teal-700 transition-all duration-300 shadow-lg hover:shadow-xl">
            Top
          </button>
        </TooltipAdaptive>
        <div></div>
        <TooltipAdaptive
          text="Left tooltip"
          direction={getTooltipDirection("left")}
        >
          <button className="w-full px-4 py-2 text-white bg-gradient-to-b from-teal-500 to-teal-600 rounded-lg hover:from-teal-600 hover:to-teal-700 transition-all duration-300 shadow-lg hover:shadow-xl">
            Left
          </button>
        </TooltipAdaptive>
        <div className="flex items-center justify-center">
          <div className="text-sm text-gray-500 dark:text-gray-200">
            Current: {globalDirection}
          </div>
        </div>
        <TooltipAdaptive
          text="Right tooltip"
          direction={getTooltipDirection("right")}
        >
          <button className="w-full px-4 py-2 text-white bg-gradient-to-b from-teal-500 to-teal-600 rounded-lg hover:from-teal-600 hover:to-teal-700 transition-all duration-300 shadow-lg hover:shadow-xl">
            Right
          </button>
        </TooltipAdaptive>
        <div></div>
        <TooltipAdaptive
          text="Bottom tooltip"
          direction={getTooltipDirection("bottom")}
        >
          <button className="w-full px-4 py-2 text-white bg-gradient-to-b from-teal-500 to-teal-600 rounded-lg hover:from-teal-600 hover:to-teal-700 transition-all duration-300 shadow-lg hover:shadow-xl">
            Bottom
          </button>
        </TooltipAdaptive>
        <div></div>
      </div>
    </div>
  );
};

export default TooltipDemo;

Testimonial

Error Pages

On this page

Basic TooltipArrow TooltipAnimated TooltipMulti Direction Tooltip
logo

Empowering developers with intuitive and efficient UI components.

Created by Abhay Singh Rathore, a passionate Full-Stack Developer & UI/UX designer.

Quick Links

  • Home
  • Components
  • Templates

Connect

© 2025 Business Wish. All rights reserved.