Dialog
motion-primitives/dialogFreeComponent
A modal dialog component with smooth entrance and exit animations.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/ibelick/motion-primitives/HEAD/public/c/dialog.jsonSource
1'use client';2import { AnimatePresence, motion, Transition, Variants } from 'motion/react';3import React, { createContext, useContext, useEffect, useRef } from 'react';4import { cn } from '@/lib/utils';5import { useId } from 'react';6import { createPortal } from 'react-dom';7import { X } from 'lucide-react';8import { usePreventScroll } from '@/hooks/usePreventScroll';910const DialogContext = createContext<{11 isOpen: boolean;12 setIsOpen: (open: boolean) => void;13 dialogRef: React.RefObject<HTMLDialogElement | null>;14 variants: Variants;15 transition?: Transition;16 ids: {17 dialog: string;18 title: string;19 description: string;20 };21 onAnimationComplete: (definition: string) => void;22 handleTrigger: () => void;23} | null>(null);2425const defaultVariants: Variants = {26 initial: {27 opacity: 0,28 scale: 0.9,29 },30 animate: {31 opacity: 1,32 scale: 1,33 },34};3536const defaultTransition: Transition = {37 ease: 'easeOut',38 duration: 0.2,39};4041export type DialogProps = {42 children: React.ReactNode;43 variants?: Variants;44 transition?: Transition;45 className?: string;46 defaultOpen?: boolean;47 onOpenChange?: (open: boolean) => void;48 open?: boolean;49};5051function Dialog({52 children,53 variants = defaultVariants,54 transition = defaultTransition,55 defaultOpen,56 onOpenChange,57 open,58}: DialogProps) {59 const [uncontrolledOpen, setUncontrolledOpen] = React.useState(60 defaultOpen || false61 );62 const dialogRef = useRef<HTMLDialogElement>(null);63 const isOpen = open !== undefined ? open : uncontrolledOpen;6465 // prevent scroll when dialog is open on iOS66 usePreventScroll({67 isDisabled: !isOpen,68 });6970 const setIsOpen = React.useCallback(71 (value: boolean) => {72 setUncontrolledOpen(value);73 onOpenChange?.(value);74 },75 [onOpenChange]76 );7778 useEffect(() => {79 const dialog = dialogRef.current;80 if (!dialog) return;8182 if (isOpen) {83 document.body.classList.add('overflow-hidden');84 } else {85 document.body.classList.remove('overflow-hidden');86 }8788 const handleCancel = (e: Event) => {89 e.preventDefault();90 if (isOpen) {91 setIsOpen(false);92 }93 };9495 dialog.addEventListener('cancel', handleCancel);96 return () => {97 dialog.removeEventListener('cancel', handleCancel);98 document.body.classList.remove('overflow-hidden');99 };100 }, [dialogRef, isOpen, setIsOpen]);101102 useEffect(() => {103 if (isOpen && dialogRef.current) {104// … truncated
What it pulls in
npm packages
Files it writes
More from motion-primitives
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | motion-primitives | Components | Free | 1 dep | |
| Animated Backgroundanimated-background | motion-primitives | Components | Free | 1 dep | |
| Animated Groupanimated-group | motion-primitives | Components | Free | 1 dep | |
| Animated Numberanimated-number | motion-primitives | Components | Free | 1 dep | |
| Border Trailborder-trail | motion-primitives | Components | Free | 1 dep | |
| Carouselcarousel | motion-primitives | Components | Free | 1 dep | |
| Cursorcursor | motion-primitives | Components | Free | 1 dep | |
| Disclosuredisclosure | motion-primitives | Components | Free | 1 dep |
