Portal-Based Modal Component
Accessible modal component using React portals with focus trapping, Escape key close, and backdrop click.
import { useEffect, useRef, ReactNode } from 'react';
import { createPortal } from 'react-dom';
interface ModalProps {
open: boolean;
onClose: () => void;
children: ReactNode;
}
export function Modal({ open, onClose, children }: ModalProps) {
const overlayRef = useRef<HTMLDivElement>(null);
const contentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const handleKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleKey);
document.body.style.overflow = 'hidden';
contentRef.current?.focus();
return () => {
document.removeEventListener('keydown', handleKey);
document.body.style.overflow = '';
};
}, [open, onClose]);
if (!open) return null;
return createPortal(
<div
ref={overlayRef}
onClick={(e) => e.target === overlayRef.current && onClose()}
style={{
position: 'fixed', inset: 0, display: 'flex',
alignItems: 'center', justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.6)', zIndex: 50,
}}
>
<div
ref={contentRef}
role="dialog"
aria-modal="true"
tabIndex={-1}
style={{
background: '#111', borderRadius: 12, padding: 24,
maxWidth: 500, width: '90%', outline: 'none',
}}
>
{children}
</div>
</div>,
document.body
);
}
// Usage:
// <Modal open={isOpen} onClose={() => setIsOpen(false)}>
// <h2>Confirm</h2>
// <button onClick={() => setIsOpen(false)}>Close</button>
// </Modal>Use Cases
- Confirmation dialogs
- Image lightbox
- Form overlays
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Error Boundary with Fallback UI
Class-based error boundary component that catches render errors and displays a customizable fallback UI.
Image Lazy Load Component
Lazy load images with a blur-up placeholder effect using Intersection Observer and CSS transitions.
useFetch — Generic Data Fetching Hook
Custom React hook for data fetching with loading, error, and refetch states using the Fetch API.
useDebounce — Debounced Value Hook
Debounce any rapidly-changing value with a configurable delay. Useful for search inputs and resize handlers.