Introduction

react-morphcard is a React hook that grows a card into a detail view and shrinks it back, with the card's title, name and badge flying into the header.

Every card below opens with the library. Click one: it grows into a preview of that page, its icon and title fly into the header, and Back, Esc or a click outside shrinks it back onto the card.

Start

Getting started

Install from npm, add three elements, call useMorph.

Try it

Playground

Change duration, easing, stagger and speed, then click the tiles.

Reference

API reference

Every option of useMorph, what it returns, and the data attributes.

How it works

Anatomy

What moves when, with every duration and easing.

How it works

Interruptions

Back during an open turns the same animations around.

How it works

Accessibility

Reduced motion is opacity only. Focus goes in and comes back.

How it works

Pitfalls

Seven bugs from a real app, each now a rule and a test.

Guides

Recipes

List to detail with a URL, a photo gallery, a wallet card.

Guides

vs View Transitions

When the browser API is enough and when it is not.

react-morphcard does one transition. You give useMorph three elements (the detail sheet, the content behind it and an optional scrim) and mark the parts that should travel with data-morph. When a card is clicked, it measures both ends and plays the transition with the Web Animations API.

import { useMorph } from "react-morphcard";

What you get

  • A single surface. The sheet is clipped to the card's rectangle and the clip opens to its full size. Text inside is never scaled as a bitmap, so it stays sharp.
  • Shared elements. Anything marked data-morph="key" on the card and in the sheet flies between the two. Text that wraps differently on each side crossfades while it flies.
  • A separate close. Closing takes 300 ms against 400 ms for opening. The big heading hands over to the card's own text in the first 90 ms.
  • Interruptions. Close during an open and the running animations turn around from where they are.
  • Safe fallbacks. No card on screen, no destination, or reduced motion: it fades instead of flying.
  • No other dependencies. React 18 or 19 and nothing else.

Where it runs

Desktop and mobile browsers, installed PWAs and WebViews: anywhere React DOM runs. The sheet can be a centred panel, as on this site, or cover the whole screen, as in a phone app. It does not support React Native.

Watch it slowed down

Open and back

4× slower

On a desktop

1×

The anatomy page takes this transition apart on a timeline you can scrub, with every duration and easing.

Browser support

The hook uses Element.animate, animates clip-path: inset() and sets the inert attribute. inert is the newest of these: Chrome and Edge 102, Firefox 112, Safari 15.5 (caniuse). The automated tests run in Chromium only so far.

Status

Version 0.1. The API is small and may still change before 1.0. Install it from npm as shown in Getting started.

Made by Lucas Piera