Tooltip
The following tooltip component is a single and highly customizable component, you can trigger it via clicking on an element or hovering it. You can set various positions, predefined variants (And can define your own) and delay but also it is highly customizable via Tailwind. It is very versatile
No extra libraries required. Assuming you have Tailwind CSS installed
// App.jsximport React from 'react';import Tooltip from './components/tooltip';
const App = () => { return ( <div className="flex justify-center items-center h-screen space-x-4"> <Tooltip content="This is a default tooltip!" variant="default" position="top" trigger="hover" delay={200}> <button className="px-4 py-2 bg-gray-800 text-white rounded">Hover me (Default)</button> </Tooltip> <Tooltip content="Click for success tooltip!" variant="success" position="bottom" trigger="click" delay={100}> <button className="px-4 py-2 bg-gray-800 text-white rounded">Click me (Success)</button> </Tooltip> <Tooltip content="This is an error tooltip!" variant="error" position="left" trigger="hover" delay={300}> <button className="px-4 py-2 bg-red-800 text-white rounded">Hover me (Error)</button> </Tooltip> <Tooltip content="This is an info tooltip!" variant="info" position="right" trigger="click" delay={150}> <button className="px-4 py-2 bg-gray-800 text-white rounded">Click me (Info)</button> </Tooltip> </div> );};
export default App;
// Tooltip.jsximport React, { useState, useEffect, useRef } from 'react';
const Tooltip = ({ children, content, variant = 'default', position = 'right', size = 'base', trigger = 'hover', delay = 100, className = '', style = {},}) => { const [isVisible, setIsVisible] = useState(false); const timeoutRef = useRef(null);
const tooltipClasses = { default: 'bg-gray-700 text-white', success: 'bg-green-500 text-white', error: 'bg-red-500 text-white', info: 'bg-blue-500 text-white', warning: 'bg-yellow-400 text-black', dark: 'bg-gray-900 text-white', light: 'bg-white text-black border border-gray-300', };
const sizeClasses = { large: 'p-3 text-sm', base: 'p-2 text-sm', // Base size small: 'p-1 text-xs', };
const positionClasses = { top: 'bottom-full mb-2 left-1/2 transform -translate-x-1/2', bottom: 'top-full mt-2 left-1/2 transform -translate-x-1/2', left: 'right-full mr-2 top-1/2 transform -translate-y-1/2', right: 'left-full ml-2 top-1/2 transform -translate-y-1/2', };
const showTooltip = () => { if (timeoutRef.current) clearTimeout(timeoutRef.current); timeoutRef.current = setTimeout(() => setIsVisible(true), delay); };
const hideTooltip = () => { if (timeoutRef.current) clearTimeout(timeoutRef.current); setIsVisible(false); };
useEffect(() => { return () => { if (timeoutRef.current) clearTimeout(timeoutRef.current); }; }, []);
const handleMouseEnter = () => { if (trigger === 'hover') showTooltip(); }; const handleMouseLeave = () => { if (trigger === 'hover') hideTooltip(); };
const handleClick = () => { if (trigger === 'click') { setIsVisible((prev) => !prev); } };
return ( <div className="relative inline-block" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} onClick={handleClick} aria-describedby="tooltip" > {children} {isVisible && ( <div id="tooltip" role="tooltip" className={`absolute p-2 rounded shadow-lg ${tooltipClasses[variant]} transition-opacity duration-300 ${positionClasses[position]} ${className} ${sizeClasses[size]}`} style={style} > {content} </div> )} </div> );};
export default Tooltip;