Skip to content
← Inventory

MorphDialog

Root of a dialog that morphs open from its trigger via a shared-element layout animation — the trigger and the dialog card share a layoutId, so Motion tweens position, size, radius, and shadow between them. Controlled when open is passed, otherwise uncontrolled. Provides context to the trigger, content, title, and description parts.

Sample request

A cut sample of Terrazzo Bianco ships to your studio in 3–5 days.

Usage

import { MorphDialog, MorphDialogContent, MorphDialogDescription, MorphDialogTitle, MorphDialogTrigger, useMorphDialog } from "@desk/ui/components/morph-dialog";

Best practices

  • Reach for MorphDialog only when the modal should animate out of its trigger element (shared-layout); a plain centered modal is a Dialog.

  • Pass the trigger's borderRadius / boxShadow via style (not className) on MorphDialogTrigger so Motion can correct their distortion during the morph.

  • Render a MorphDialogTitle (use visuallyHidden if needed) for the accessible name; mount ReducedMotionProvider at the app root since it animates via m.*.

Props

MorphDialog

PropTypeDefaultDescription
children(required)import("react").ReactNode
onOpenChange(open: boolean) => void

Callback when open state changes

openboolean

Controlled open state. Omit to let the dialog manage its own open state.

MorphDialogContent

PropTypeDefaultDescription
children(required)import("react").ReactNode
classNamestring
data-testidstring

Test ID for E2E testing

position"center" | "bottom"

Position of the dialog. "center" (default) centers in viewport, "bottom" anchors near bottom for thumb reach

MorphDialogDescription

PropTypeDefaultDescription
children(required)import("react").ReactNode
classNamestring
visuallyHiddenboolean

Visually hide but keep accessible to screen readers

MorphDialogTitle

PropTypeDefaultDescription
children(required)import("react").ReactNode
classNamestring
visuallyHiddenboolean

Visually hide but keep accessible to screen readers

MorphDialogTrigger

PropTypeDefaultDescription
children(required)import("react").ReactNode
classNamestring
styleimport("react").CSSProperties

Style props for the layoutId element (the one that morphs). Motion can only auto-correct borderRadius and boxShadow distortion if they're set via style prop, not className. Pass matching values from your trigger children here.

Also exports

  • constuseMorphDialog