Dialog / Modal
ComponentsModal windows with overlay.
Edit Profile
Make changes to your profile here. Click save when you're done.
Live Functional Playground Interactive Hooks • useState
Confirm Deployment
Are you sure you want to promote build #492 to production? This will instantly switch live CDN traffic.
Motion Physics & Animation Showcase Framer Motion ✨
Spring Animated Modal
Smooth entrance with spring physics and backdrop blur.
Format:
Required Animation Library: framer-motion & lucide-react
Install this package in your project before importing the animated component.
npm i framer-motion lucide-react <div class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm flex items-center justify-center p-4">
<div class="w-full max-w-lg rounded-xl border border-border bg-card text-card-foreground shadow-lg p-6">
<h3 class="font-semibold text-lg mb-2">Edit Profile</h3>
<p class="text-sm text-muted-foreground mb-4">Make changes to your profile here. Click save when you're done.</p>
<div class="flex justify-end space-x-2 mt-6">
<button class="px-4 py-2 text-sm font-medium rounded-md border border-input bg-background shadow-sm hover:bg-accent">Cancel</button>
<button class="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground shadow hover:bg-primary/90">Save Changes</button>
</div>
</div>
</div> <div className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm flex items-center justify-center p-4">
<div className="w-full max-w-lg rounded-xl border border-border bg-card text-card-foreground shadow-lg p-6">
<h3 className="font-semibold text-lg mb-2">Edit Profile</h3>
<p className="text-sm text-muted-foreground mb-4">Make changes to your profile here. Click save when you're done.</p>
<div className="flex justify-end space-x-2 mt-6">
<button className="px-4 py-2 text-sm font-medium rounded-md border border-input bg-background shadow-sm hover:bg-accent">Cancel</button>
<button className="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground shadow hover:bg-primary/90">Save Changes</button>
</div>
</div>
</div> "use client";
import React, { useState, useEffect } from "react";
interface DialogProps {
title?: string;
description?: string;
triggerText?: string;
confirmText?: string;
onConfirm?: () => void;
}
export default function Dialog({
title = "Edit Profile",
description = "Make changes to your profile here. Click save when you're done.",
triggerText = "Open Modal",
confirmText = "Save Changes",
onConfirm,
}: DialogProps) {
const [isOpen, setIsOpen] = useState(false);
// Close when pressing the Escape key
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") setIsOpen(false);
};
if (isOpen) {
document.addEventListener("keydown", handleKeyDown);
document.body.style.overflow = "hidden";
}
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.body.style.overflow = "unset";
};
}, [isOpen]);
return (
<>
<button
type="button"
onClick={() => setIsOpen(true)}
className="px-4 py-2 text-sm font-semibold rounded-xl bg-primary text-primary-foreground hover:bg-primary/90 transition-all shadow-sm active:scale-95"
>
{triggerText}
</button>
{isOpen && (
<div
className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4 animate-in fade-in duration-200"
onClick={() => setIsOpen(false)}
>
<div
className="w-full max-w-lg rounded-2xl border border-border bg-card text-card-foreground shadow-2xl p-6 relative animate-in zoom-in-95 duration-200"
onClick={(e) => e.stopPropagation()}
role="dialog"
aria-modal="true"
>
<h3 className="font-bold text-xl text-foreground mb-1.5">{title}</h3>
<p className="text-sm text-muted-foreground mb-6 leading-relaxed">{description}</p>
<div className="flex justify-end gap-3 mt-6">
<button
type="button"
onClick={() => setIsOpen(false)}
className="px-4 py-2 text-sm font-medium rounded-lg border border-border bg-background hover:bg-muted text-foreground transition-colors"
>
Cancel
</button>
<button
type="button"
onClick={() => {
onConfirm?.();
setIsOpen(false);
}}
className="px-4 py-2 text-sm font-semibold rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm transition-colors"
>
{confirmText}
</button>
</div>
</div>
</div>
)}
</>
);
} "use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { X } from "lucide-react";
export default function AnimatedDialog() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<motion.button
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
onClick={() => setIsOpen(true)}
className="px-5 py-2.5 text-xs font-semibold rounded-xl bg-primary text-primary-foreground shadow-md hover:bg-primary/90 transition-colors"
>
Open Animated Dialog
</motion.button>
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
{/* Backdrop with fade animation */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 bg-black/60 backdrop-blur-sm"
onClick={() => setIsOpen(false)}
/>
{/* Modal Box with spring scale & slide */}
<motion.div
initial={{ opacity: 0, scale: 0.92, y: 15 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.94, y: 10 }}
transition={{ type: "spring", damping: 25, stiffness: 350 }}
className="w-full max-w-lg rounded-2xl border border-border/80 bg-card p-6 shadow-2xl relative z-10"
role="dialog"
aria-modal="true"
>
<button
type="button"
onClick={() => setIsOpen(false)}
className="absolute top-4 right-4 p-1.5 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
>
<X className="h-4 w-4" />
</button>
<h3 className="font-bold text-xl text-foreground mb-1">Edit Profile</h3>
<p className="text-xs text-muted-foreground mb-6 leading-relaxed">
Make changes to your profile parameters here. Click save when you're done.
</p>
<div className="flex justify-end gap-3 mt-6">
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="button"
onClick={() => setIsOpen(false)}
className="px-4 py-2 text-xs font-medium rounded-lg border border-border bg-background hover:bg-muted text-foreground transition-colors"
>
Cancel
</motion.button>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="button"
onClick={() => setIsOpen(false)}
className="px-4 py-2 text-xs font-semibold rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm transition-colors"
>
Save Changes
</motion.button>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
</>
);
}