typescriptintermediate
Portal Tooltip Component
Accessible tooltip rendered via Portal with automatic positioning and arrow indicator.
typescriptPress ⌘/Ctrl + Shift + C to copy
import { useState, useRef, useEffect, ReactNode } from 'react';
import { createPortal } from 'react-dom';
interface TooltipProps {
content: string;
children: ReactNode;
position?: 'top' | 'bottom';
}
export function Tooltip({ content, children, position = 'top' }: TooltipProps) {
const [visible, setVisible] = useState(false);
const [coords, setCoords] = useState({ top: 0, left: 0 });
const triggerRef = useRef<HTMLSpanElement>(null);
useEffect(() => {
if (!visible || !triggerRef.current) return;
const rect = triggerRef.current.getBoundingClientRect();
setCoords({
top: position === 'top' ? rect.top + window.scrollY - 8 : rect.bottom + window.scrollY + 8,
left: rect.left + window.scrollX + rect.width / 2,
});
}, [visible, position]);
return (
<>
<span
ref={triggerRef}
onMouseEnter={() => setVisible(true)}
onMouseLeave={() => setVisible(false)}
aria-describedby={visible ? 'tooltip' : undefined}
>
{children}
</span>
{visible && createPortal(
<div
id="tooltip"
role="tooltip"
className="fixed px-2 py-1 bg-gray-800 text-white text-xs rounded shadow-lg -translate-x-1/2 whitespace-nowrap z-50"
style={{ top: coords.top, left: coords.left, transform: `translateX(-50%) translateY(${position === 'top' ? '-100%' : '0'})` }}
>
{content}
</div>,
document.body
)}
</>
);
}Use Cases
- Icon button labels
- Abbreviated text explanations
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptintermediate
Portal-Based Modal Component
Accessible modal component using React portals with focus trapping, Escape key close, and backdrop click.
Best for: Confirmation dialogs
#modal#portal
typescriptintermediate
Accordion Component
Accessible accordion component with keyboard navigation and animated expand/collapse.
Best for: FAQ sections
#accordion#a11y
typescriptintermediate
Portal Dropdown Component
Dropdown menu rendered via Portal to avoid overflow clipping, with click-outside dismiss.
Best for: Navigation menus
#portal#dropdown
typescriptintermediate
Error Boundary with Fallback UI
Class-based error boundary component that catches render errors and displays a customizable fallback UI.
Best for: Graceful error recovery
#error-boundary#error-handling