1const [isOpen, setIsOpen] = useState(false);23<button Installation
npx zeroui@latest add modal-baseInstall dependencies
npm install lucide-reactCopy the component code
Create a new file and paste the following code:
components/modals/modal-base.tsx
"use client";
import React, { useEffect, useState } from "react";
import { X } from "lucide-react";
interface ModalBaseProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
className?: string;
}
export default function ModalBase({
isOpen,
onClose,
title,
children,
className = "",
}: ModalBaseProps) {
const [isVisible, setIsVisible] = useState(false);
const [isAnimating, setIsAnimating] = useState(false);
useEffect(() => {
if (isOpen) {
setIsVisible(true);
requestAnimationFrame(() => setIsAnimating(true));
} else {
setIsAnimating(false);
const timer = setTimeout(() => setIsVisible(false), 300);
return () => clearTimeout(timer);
}
}, [isOpen]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape" && isOpen) {
onClose();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [isOpen, onClose]);
if (!isVisible) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<div
className={`absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300 ${
isAnimating ? "opacity-100" : "opacity-0"
}`}
onClick={onClose}
/>
<div
className={`relative w-full max-w-lg bg-white dark:bg-zinc-900 rounded-xl shadow-2xl transform transition-all duration-300 ease-out ${
isAnimating ? "scale-100 opacity-100 translate-y-0" : "scale-95 opacity-0 translate-y-4"
} ${className}`}
>
<div className="flex items-center justify-between px-6 py-4 border-b border-zinc-200 dark:border-zinc-800">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-white">
{title}
</h3>
<button
onClick={onClose}
className="p-1 rounded-md text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors"
>
<X size={20} />
</button>
</div>
<div className="p-6">{children}</div>
</div>
</div>
);
}Props
| name | type | default | description |
|---|---|---|---|
| isOpen | boolean | false | Controls visibility |
| onClose | () => void | - | Close handler |
| title | string | - | Modal header title |
| children | ReactNode | - | Modal content |