Morphing Modal

Dialog that moves between several views inside one panel.

Installation

pnpm dlx shadcn@latest add @paneui/morphing-modal

Usage

Composition

Examples

Multi-step Flow

Nested Settings

Without Close Button

Use for confirmations that should end with an explicit choice.

Motion

The panel springs to each view's height while views slide 28px and blur in the direction of travel. With reduced motion the height snaps and views cross-fade in 150ms.

Accessibility

After navigating, focus moves to the first focusable control in the new view (or the view itself). Closing resets to the first view once the exit finishes.

API Reference

Built on the Dialog primitive. Only the props this library adds or changes are listed; everything else passes through.

MorphingModal

Dialog root that also holds the view stack. Also accepts every prop of Dialog.Root.

defaultView= "main"
string
The view shown when the modal opens.
onViewChange
(view: string) => void
Called once with the new view whenever it changes, including the reset to defaultView when the modal finishes closing.
PropTypeDefaultDescription
defaultViewstring"main"The view shown when the modal opens.
onViewChange(view: string) => void—Called once with the new view whenever it changes, including the reset to defaultView when the modal finishes closing.

MorphingModalTrigger

Dialog.Trigger, re-exported unchanged. Also accepts every prop of Dialog.Trigger.

MorphingModalContent

Backdrop and centred popup (max 384px wide). Renders the active MorphingModalView child; other children render after it. Also accepts every prop of Dialog.Popup.

showCloseButton= true
boolean
Show the round × in the top-right corner.
PropTypeDefaultDescription
showCloseButtonbooleantrueShow the round × in the top-right corner.

MorphingModalView

One screen of the modal. Must be a direct child of MorphingModalContent. Also accepts every prop of div.

name*
string
Identifier other parts navigate to.
PropTypeDefaultDescription
name*string—Identifier other parts navigate to.
data-view
The view's name.
Data attributeDescription
data-viewThe view's name.

MorphingModalHeader

Title block; shows MorphingModalBack automatically when there is a view to go back to. Also accepts every prop of div.

MorphingModalTitle

Also accepts every prop of Dialog.Title.

MorphingModalDescription

Also accepts every prop of Dialog.Description.

A full-width row button that pushes another view. Also accepts every prop of button.

to*
string
Name of the view to open.
PropTypeDefaultDescription
to*string—Name of the view to open.

MorphingModalBack

Round back chevron labelled Back. Renders nothing on the first view. Also accepts every prop of button.

MorphingModalFooter

Right-aligned row of actions. Also accepts every prop of div.

MorphingModalClose

Dialog.Close, re-exported unchanged. Also accepts every prop of Dialog.Close.

useMorphingModal

Navigation state for custom controls. Use inside MorphingModal.

view
string
The active view.
canGoBack
boolean
Whether there is a previous view.
direction
1 | -1
Direction of the last navigation.
push
(view: string) => void
Go to a view (pushes it onto the back stack).
back
() => void
Return to the previous view.
reset
() => void
Jump back to the first view and clear the stack (calls onViewChange if the view changes).
PropTypeDefaultDescription
viewstring—The active view.
canGoBackboolean—Whether there is a previous view.
direction1 | -1—Direction of the last navigation.
push(view: string) => void—Go to a view (pushes it onto the back stack).
back() => void—Return to the previous view.
reset() => void—Jump back to the first view and clear the stack (calls onViewChange if the view changes).