Fiber UI LogoFiberUI

Tooltip

A popup that displays information related to an element when the element receives focus or is hovered.

Basic Usage

import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";

/* BASIC USAGE EXAMPLE */
export const Example1 = () => {
    return (
        <TooltipTrigger>
            <Button variant="outline">Hover me</Button>
            <TooltipContent>Add to library</TooltipContent>
        </TooltipTrigger>
    );
};

Placement

import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";

/* TOOLTIP PLACEMENT EXAMPLE */
export const Example2 = () => {
    return (
        <div className="flex flex-wrap items-center justify-center gap-4">
            <TooltipTrigger>
                <Button variant="outline">Top</Button>
                <TooltipContent placement="top">Top tooltip</TooltipContent>
            </TooltipTrigger>

            <TooltipTrigger>
                <Button variant="outline">Bottom</Button>
                <TooltipContent placement="bottom">
                    Bottom tooltip
                </TooltipContent>
            </TooltipTrigger>

            <TooltipTrigger>
                <Button variant="outline">Left</Button>
                <TooltipContent placement="left">Left tooltip</TooltipContent>
            </TooltipTrigger>

            <TooltipTrigger>
                <Button variant="outline">Right</Button>
                <TooltipContent placement="right">Right tooltip</TooltipContent>
            </TooltipTrigger>
        </div>
    );
};

With Icon Buttons

import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";
import { Info, HelpCircle, Settings } from "lucide-react";

/* TOOLTIP WITH ICON BUTTONS */
export const Example3 = () => {
    return (
        <div className="flex items-center gap-2">
            <TooltipTrigger>
                <Button variant="ghost" size="icon">
                    <Info className="size-4" />
                </Button>
                <TooltipContent>More information</TooltipContent>
            </TooltipTrigger>

            <TooltipTrigger>
                <Button variant="ghost" size="icon">
                    <HelpCircle className="size-4" />
                </Button>
                <TooltipContent>Help & Support</TooltipContent>
            </TooltipTrigger>

            <TooltipTrigger>
                <Button variant="ghost" size="icon">
                    <Settings className="size-4" />
                </Button>
                <TooltipContent>Settings</TooltipContent>
            </TooltipTrigger>
        </div>
    );
};

Component Code

"use client";
import React from "react";
import {
    Tooltip as AriaTooltip,
    TooltipTrigger as AriaTooltipTrigger,
    TooltipProps as AriaTooltipProps,
    TooltipTriggerComponentProps,
    OverlayArrow,
    composeRenderProps,
} from "react-aria-components";
import { tv } from "tailwind-variants";

import { cn } from "tailwind-variants";

const tooltipStyles = tv({
    base: "bg-secondary text-secondary-foreground z-50 rounded-md px-3 py-1.5 text-xs shadow-md",
    variants: {
        isEntering: {
            true: "animate-in fade-in-0 zoom-in-95 duration-200",
        },
        isExiting: {
            true: "animate-out fade-out-0 zoom-out-95 duration-150",
        },
    },
});

export interface TooltipProps extends Omit<AriaTooltipProps, "children"> {
    children: React.ReactNode;
}

export const TooltipTrigger = (props: TooltipTriggerComponentProps) => {
    return <AriaTooltipTrigger delay={750} {...props} />;
};

export const TooltipContent = ({
    children,
    className,
    ...props
}: TooltipProps) => {
    return (
        <AriaTooltip
            data-slot="tooltip"
            offset={8}
            {...props}
            className={composeRenderProps(
                className,
                (className, renderProps) =>
                    cn(tooltipStyles({ ...renderProps }), className) || "",
            )}
        >
            <OverlayArrow>
                {({ placement }) => (
                    <svg
                        width={8}
                        height={8}
                        viewBox="0 0 8 8"
                        className={cn(
                            "fill-secondary scale-110",
                            placement?.startsWith("top") && "",
                            placement?.startsWith("bottom") && "-rotate-180",
                            placement?.startsWith("right") && "rotate-90",
                            placement?.startsWith("left") && "-rotate-90",
                        )}
                    >
                        <path d="M0 0 L4 4 L8 0" />
                    </svg>
                )}
            </OverlayArrow>
            {children}
        </AriaTooltip>
    );
};