Back to Snippets
ReactTypeScript

React Modal Component

A reusable modal dialog with backdrop, keyboard handling, and portal rendering.

reactcomponentmodaldialog
import { useEffect, type ReactNode } from class=class="text-emerald-400">"text-emerald-400">'react'
import { createPortal } from class=class="text-emerald-400">"text-emerald-400">'react-dom'

interface ModalProps {
  isOpen: boolean
  onClose: () => void
  children: ReactNode
  title?: string
}

export function Modal({ isOpen, onClose, children, title }: ModalProps) {
  useEffect(() => {
    const handleEsc = (e: KeyboardEvent) => {
      if (e.key === class=class="text-emerald-400">"text-emerald-400">'Escape') onClose()
    }
    if (isOpen) {
      document.addEventListener(class=class="text-emerald-400">"text-emerald-400">'keydown', handleEsc)
      document.body.style.overflow = class=class="text-emerald-400">"text-emerald-400">'hidden'
    }
    return () => {
      document.removeEventListener(class=class="text-emerald-400">"text-emerald-400">'keydown', handleEsc)
      document.body.style.overflow = class=class="text-emerald-400">"text-emerald-400">''
    }
  }, [isOpen, onClose])

  if (!isOpen) return null

  return createPortal(
    <div className=class="text-emerald-400">"fixed inset-0 z-50 flex items-center justify-center">
      <div className=class="text-emerald-400">"absolute inset-0 bg-black/50" onClick={onClose} />
      <div className=class="text-emerald-400">"relative bg-white rounded-lg p-6 max-w-md w-full mx-4 shadow-xl">
        {title && <h2 className=class="text-emerald-400">"text-lg font-semibold mb-4">{title}</h2>}
        {children}
      </div>
    </div>,
    document.body
  )
}

How to Use

Control visibility with state: <Modal isOpen={open} onClose={() => setOpen(false)} title="Confirm">Content here</Modal>. It closes on Escape key, locks body scroll, and renders via a portal.

Related Technology

React

Have a Project in Mind?

Let's discuss how we can bring your idea to life. From initial concept to production-ready product — we've got you covered.

or book a free call