Compared with View Transitions

Choosing between native transitions, React ViewTransition, Motion and react-morphcard.

View Transitions can implement a card-to-detail transition. Choose react-morphcard for its specific interaction contract: a mounted detail sheet, shared elements, Back that reverses the current flight, scroll restoration and visibility fallbacks. It is not a general replacement for the browser API or an animation framework.

Choose for the interaction

RequirementStarting point
Navigation between pages or replacement of an entire viewNative View Transitions, or your router's integration
React updates coordinated with Suspense and transitionsReact <ViewTransition>
Reordering layouts, gestures, springs and many kinds of shared elementsMotion layout / layoutId
A card opening a mounted sheet, with immediate reversal on Backreact-morphcard

These are recommendations, not performance rankings. Profile the actual page on target devices before claiming one approach is faster.

What the browser and React already provide

Native View Transitions capture the old and new views and animate their pseudo-elements. Starting another document transition skips the active one; it does not automatically reverse its progress. Custom scheduling and animation control can change that behaviour. See the View Transitions specification.

React's <ViewTransition> coordinates capture with React commits. Its documented scheduling finishes the current React transition and batches queued updates into the next one. It also handles shared boundaries outside the viewport by using enter/exit behaviour. You still configure reduced motion. See the React reference.

Do not assume View Transitions always block the whole page or allow only one independent animation. Chrome 147 added element-scoped transitions, including concurrent and nested transitions; the rest of the page can stay interactive. Check support separately from document-level transitions. See Chrome's element-scoped API.

What react-morphcard adds

The hook animates the actual sheet and shared elements through WAAPI, plus a temporary copy of the card. It owns a narrow choreography:

  • Back reverses the same run at its current position, including before opening has finished.
  • Partially visible cards grow from their visible portion; entirely hidden or missing cards use an opacity fallback.
  • Text that wraps differently uses two moving copies and a crossfade.
  • Reduced motion, scroll restoration, return focus, and cleanup are included.
  • open({ key, item }) updates the mounted detail before geometry is measured.

That behaviour comes with maintenance cost: DOM measurement, clipping, copies, focus and browser-specific animation details. Native capture avoids maintaining some of that machinery. The published, unminified ESM build measured about 15.4 kB gzipped during the September 2026 review, excluding React; consumer minification and tree shaking change the result.

When Motion is the better fit

Motion's layout and layoutId support layout and shared-element animation, with AnimatePresence for exits and options for scroll/fixed layouts. If the app already uses Motion for gestures and springs, build the sheet there before adding another animation dependency. See Motion layout animations.

Combining approaches

Use separate ownership boundaries: for example, route navigation through React ViewTransition and card details through react-morphcard. Avoid scheduling both on the same subtree at the same time. In particular, this hook uses flushSync before measurement, which can cause React to skip a pending ViewTransition. Let one interaction finish or skip before starting the other.

The hook is an animation primitive, not a complete modal system. See Accessibility for the surrounding dialog's responsibilities.

Made by Lucas Piera