Morph modal
100xui/morph-modalFreeBlock
A reusable modal component that smoothly 'morphs' from the dimensions and position of its trigger element
Live preview
live · rendered by the registry
Rendered by 100xui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://100xui.com/r/morph-modal.jsonSource
1"use client";23import React from "react";4import {5 AnimatePresence,6 motion,7 type HTMLMotionProps,8 type Transition,9} from "motion/react";10import { cn } from "@/lib/utils";1112function assertOnlyChild(children: React.ReactNode) {13 if (Array.isArray(children))14 throw new Error(15 "A single child is required, but received multiple siblings."16 );17 if (18 children &&19 React.isValidElement(children) &&20 children.type === React.Fragment &&21 Array.isArray((children.props as React.FragmentProps).children)22 )23 throw new Error(24 "A single child is required; fragments that render multiple siblings are not allowed."25 );26}2728type MorphModalContextType = {29 openModal: boolean;30 setOpenModal: React.Dispatch<React.SetStateAction<boolean>>;31 modalId: string;32 transition: Transition;33};3435const MorphModalContext = React.createContext<36 MorphModalContextType | undefined37>(undefined);3839export const useMorphModal = () => {40 const ctx = React.useContext(MorphModalContext);41 if (!ctx)42 throw new Error("useMorphModal must be used within a <MorphModal />");43 return ctx;44};4546interface MorphModalProps {47 children: React.ReactNode;48 transition?: Omit<Transition, "delay">;49}5051const DEFAULT_DURATION = 0.3;52const DEFAULT_EASE = "easeInOut";5354export function MorphModal({ children, transition }: MorphModalProps) {55 const modalId = React.useId();56 const [openModal, setOpenModal] = React.useState(false);5758 return (59 <MorphModalContext.Provider60 value={{61 openModal,62 setOpenModal,63 modalId,64 transition: {65 duration: DEFAULT_DURATION,66 ease: DEFAULT_EASE,67 ...transition,68 },69 }}70 >71 {children}72 </MorphModalContext.Provider>73 );74}7576interface MorphModalTriggerProps extends HTMLMotionProps<"button"> {77 children: React.ReactNode;78}7980export function MorphModalTrigger({81 children,82 className,83 onClick,84 ...rest85}: MorphModalTriggerProps) {86 assertOnlyChild(children);8788 const { openModal, setOpenModal, transition, modalId } = useMorphModal();89 const { duration, ...restTransition } = transition;9091 return (92 <div className="relative">93 <AnimatePresence initial={false}>94 {!openModal && (95 <motion.button96 onClick={(e) => {97 setOpenModal(true);98 onClick?.(e);99 }}100// … truncated
What it pulls in
npm packages
Files it writes
More from 100xui
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple galleryapple-gallery | 100xui | Blocks | Free | 1 dep | |
| Chat bento cardchat-bento-card | 100xui | Blocks | Free | 1 dep | |
| demosdemos | 100xui | Blocks | Free | no deps · 12 files | |
| In-page navbarin-page-navbar | 100xui | Blocks | Free | 1 dep · 2 files | |
| internalsinternals | 100xui | Blocks | Free | no deps · 4 files | |
| iPhone 3D mockupiphone-3d-mockup | 100xui | Blocks | Free | no deps | |
| Menu wheelmenu-wheel | 100xui | Blocks | Free | 1 dep | |
| Motion Dockmotion-dock | 100xui | Blocks | Free | 1 dep · 3 files |
