Morphing Modal

Pro

Multi-step modal that smoothly resizes to fit each page as content swaps in place. It grows out of the button that opened it, confirms with a check, then closes back into it.

Preview

Installation

npx @lumioui/cli add pro/morphing-modal

Usage

import { MorphingModal } from "@/components/ui/morphing-modal/morphing-modal";
<MorphingModal />

API reference

Prop Type Default
open* boolean —
onOpenChange* (open: boolean) => void —
title string

Modal title (also the accessible name). Swaps in place when it changes.

—
description string

Optional line under the title. Swaps in place when it changes.

—
showCloseButton boolean

Show the close / back control. Default true.

true
dismissible boolean

Close on backdrop press and drag. Default true.

true
swipeToDismiss boolean

Drag the panel down to dismiss. Default true.

true
placement "center" | "bottom"

"center" floats mid-screen; "bottom" rests inset above the bottom edge.

"center"
material "solid" | "glass"

Surface material. "solid" (default) or "glass" — only over photos/video.

"solid"
step number

Current step, 0-based. A change swaps the page in place; above 0 (with onBack) the close glyph becomes a back arrow.

—
stepCount number

Number of steps — drives the step track and the "Step n of m" announcement.

—
onBack () => void

Go back one step (back arrow, Escape, Android back).

—
action MorphingModalAction

Primary button docked at the bottom of the panel, shared by every step.

—
contentKey string | number

Identity of the current page when it isn't step. A change swaps the page.

—
maxWidth number

Panel width cap; changing it springs the width. Default 400.

DEFAULT_MAX_W
originRef React.RefObject<View | null>

Grow out of this view's rect and close back into it.

—
closeInto React.RefObject<View | null>

Close by shrinking into this view instead (e.g. the card the flow was about).

—
onClosed () => void

Fires once the panel has fully left.

—
className string —
children React.ReactNode —