Dialog
An animated dialog component powered by Framer Motion, offering smooth transitions and interactive visual effects for modal windows
An animated dialog component powered by Framer Motion, offering smooth transitions and interactive visual effects for modal windows
npm install framer-motion
1import React, {2createContext,3useContext,4useState,5useEffect,6ReactNode,7} from 'react';8import { AnimatePresence, motion } from 'framer-motion';9import { X } from 'lucide-react';1011interface ModalContextProps {12open: boolean;13setOpen: (open: boolean) => void;14}1516const ModalContext = createContext<ModalContextProps | undefined>(undefined);1718const useModal = () => {19const context = useContext(ModalContext);20if (!context) {21throw new Error('useModal must be used within a ModalProvider');22}23return context;24};2526interface FramerModalProps {27children: ReactNode;28open?: boolean;29setOpen?: (open: boolean) => void;30}3132export function FramerModal({33children,34open: controlledOpen,35setOpen: controlledSetOpen,36}: FramerModalProps) {37const [internalOpen, setInternalOpen] = useState(false);38const open = controlledOpen !== undefined ? controlledOpen : internalOpen;39const setOpen =40controlledSetOpen !== undefined ? controlledSetOpen : setInternalOpen;41useEffect(() => {42if (open) {43document.body.classList.add('overflow-hidden');44} else {45document.body.classList.remove('overflow-hidden');46}4748const handleKeyDown = (event: KeyboardEvent) => {49if (event.key === 'Escape') {50setOpen(false);51}52};5354document.addEventListener('keydown', handleKeyDown);55return () => {56document.removeEventListener('keydown', handleKeyDown);57};58}, [open]);59return (60<ModalContext.Provider value={{ open, setOpen }}>61<AnimatePresence>62{open && (63<motion.div64initial={{ opacity: 0 }}65animate={{ opacity: 1 }}66exit={{ opacity: 0 }}67className='fixed inset-0 z-20 top-0 left-0 right-0 bottom-0 flex flex-col items-center w-full h-screen justify-center dark:bg-black/90 bg-white/90 backdrop-blur-sm cursor-zoom-out border'68onClick={() => setOpen(false)}69>70<motion.div71initial={{ opacity: 0, y: 8 }}72animate={{ opacity: 1, y: 0 }}73exit={{ opacity: 0, y: 8 }}74onClick={(e) => e.stopPropagation()}75className=' w-full max-w-md rounded-xl bg-white/5 p-6 backdrop-blur-2xl border'76>77<button78className='absolute top-2 right-2'79onClick={() => setOpen(false)}80>81<X />82</button>83{children}84</motion.div>85</motion.div>86)}87</AnimatePresence>88</ModalContext.Provider>89);90}9192export function ModalContent({ children }: { children: ReactNode }) {93return <>{children}</>;94}
FramerModal
Props
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | The content inside the modal. |
open | boolean | undefined | Controls the visibility of the modal. |
setOpen | (open: boolean) => void | undefined | Function to set the modal's visibility state. |
ModalContent
Props
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | The content inside the modal content area. |