Skip to content
Pinky UI

Morph Card

A card that expands into its own detail view without a cut.

  • cards
  • morph
  • depth
  • expand
  • dialog
  • shared layout
  • detail

Quick usage

usage
import { MorphCard } from "@pinky-ui/components";

<MorphCard label="Mira Odaka" expandedContent={<Details />}>
  <Preview />
</MorphCard>

Presets

Compact

Detail panel stays close to the card's size.

maxWidth={460}

Default

Comfortable reading width.

maxWidth={620}

Wide

For media or two-column detail.

maxWidth={820}

Install

Add @pinky-ui/components as a dependency, or use the CLI to copy this component's source directly into your project — no dependency to manage, fully editable.

shell
npm install @pinky-ui/components

Prefer to run the whole repository locally instead?

repository
git clone https://github.com/florash/Pinky-UI.git
cd Pinky-UI
npm install
npm run dev

Props

PropTypeDefaultDescription
expandedContentReactNodeWhat the card becomes when expanded.
labelstringAccessible name for the expanded dialog. Required.
openbooleanControlled open state. Omit to let the card own it.
onOpenChange(open: boolean) => voidCalled when the card opens or closes.
maxWidthnumber620Width of the expanded panel, in px.
radius"lg" | "xl" | "2xl""2xl"Corner radius from the shape scale.

Accessibility

  • The collapsed card is a real button with aria-expanded and aria-haspopup=dialog.
  • The expanded panel is role=dialog with aria-modal and the name you pass as `label`.
  • Escape closes it, and clicking the scrim closes it.
  • Tab is trapped inside the panel while open.
  • Focus moves to the panel's first focusable element on open and returns to the card on close.
  • Background scrolling is locked while expanded.

Reduced motion

With prefers-reduced-motion: reduce, the shared layout animation is dropped: the panel simply appears at its final size. Every behaviour — focus, Escape, the trap — is unchanged.

When to use

  • Product card to product detail
  • Profile card to full profile
  • Media card to expanded view

When not to use

  • Destructive confirmations — use a plain, unambiguous dialog
  • Long forms, which deserve their own page
  • Content that must be linkable; a dialog has no URL