Docs
Tooltip
Tooltip
Displays a positionable Tooltip component.
Its Above Me!
Heyyo, I'm a tooltip!
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!
Heyyo, I'm a tooltip!
Bottom
Its Below Me!
Heyyo, I'm a tooltip!