Skip to content

Dialog

Two modal families. MorphingModal is a view-driven panel — pass a viewId and the surface morphs between views, sized to its content; it carries every confirm ceremony. CenterMorphModal unfolds outward from its own center for single, self-contained moments, with a full focus trap.

MorphingModal — open, both placements

MorphingModal is position:fixed without a portal, so these specimens capture the genuinely open dialog inside a transformed box (the transform makes the box its containing block). The frosted backdrop blurs the portfolio content behind it.

Open — placement=bottom

Confirm send

Amount
0.245 000 00 BTC
To
bc1q…8p3w
Fee
924 sats · 6 sat/vB

Mobile posture: panel anchors to the bottom edge.

Open — placement=center

Confirm send

Amount
0.245 000 00 BTC
To
bc1q…8p3w
Fee
924 sats · 6 sat/vB
Closed

viewId=null — the layer goes inert and pointer-transparent.

import { MorphingModal } from "@coldharbor/ui";

<MorphingModal
  viewId={view} // string opens, null closes
  onClose={() => setView(null)}
  placement="center"
>
  {view === "confirm" ? <ConfirmSend /> : <Broadcasting />}
</MorphingModal>
  • --ch-bg
  • --ch-surface
  • --ch-border
  • --ch-fg
  • --ch-fg-muted
  • --ch-overlay
  • --ch-focus

View-to-view morph (live)

Switch views while open — the panel resizes around the incoming content, the old view blurs out and the new one rises in. This is the send ceremony's confirm → broadcasting hand-off.

Confirm ⇄ broadcasting

Confirm send

Amount
0.245 000 00 BTC
To
bc1q…8p3w
Fee
924 sats · 6 sat/vB
setView("broadcasting"); // same modal, new viewId — the surface morphs
  • --ch-bg
  • --ch-surface
  • --ch-border
  • --ch-fg
  • --ch-fg-muted
  • --ch-overlay
  • --ch-focus

CenterMorphModal

The panel unfolds from a folded 4% sliver at its exact center. It portals to <body> unconditionally, so the open state is shown as a static replica with the exact surface classes; the live trigger opens the real dialog (Escape, backdrop and the ✕ all dismiss; focus is trapped and returned).

Open (static replica)

Replica — the real panel cannot render inline.

Live trigger

Opens over the page; focus returns to the trigger on close.

import { CenterMorphModal, CenterMorphModalContent, CenterMorphModalTrigger } from "@coldharbor/ui";

<CenterMorphModal>
  <CenterMorphModalTrigger>
    <Button>Review send</Button>
  </CenterMorphModalTrigger>
  <CenterMorphModalContent ariaLabel="Confirm send">
    <ConfirmSend />
  </CenterMorphModalContent>
</CenterMorphModal>
  • --ch-bg
  • --ch-surface
  • --ch-border
  • --ch-fg
  • --ch-fg-muted
  • --ch-overlay
  • --ch-focus

Themes

The open panel replica under all three layers.

  • --ch-bg
  • --ch-surface
  • --ch-border
  • --ch-fg
  • --ch-fg-muted
  • --ch-overlay
  • --ch-focus