← Back to archive

Repo of the Day

shivekkhurana/react-morpheus: A morphing surface for React.js that maintains context across interactions

Published: Aug 30, 2026

Open repository ↗

A morphing surface for React.js that maintains context across interactions - shivekkhurana/react-morpheus

Summary

React Morpheus is a controlled React component that morphs a source UI element into a destination surface, animating the transition between the two states. The consuming app keeps the open state and content; Morpheus owns the measured transition and exposes a spring prop typed as a Framer Motion Transition.

What it is useful for

It fits interfaces where a control should become the next piece of UI rather than opening a detached modal or popover. Examples called out in the README include menus growing from a trigger, inspectors expanding from a list row, and command surfaces anchored to a toolbar item. Morpheus keeps three pieces explicit: the collapsed trigger, the expanded content, and an optional backdrop overlay. Because the expanded surface portals to document.body by default, it can escape clipped, transformed, or independently stacked ancestors. It is also a fit when a team wants the feel of a shared-element transition without writing its own DOM-measurement and animation code.

How engineers can use it

Install the package plus the required peer dependency:

npm i react-morpheus cuelume

Import the component and stylesheet, keep expanded in your own state, and pass both surfaces to Morpheus:

import { useState } from "react";
import { Morpheus, MorphAnchor, morphSpringPresets } from "react-morpheus";
import "react-morpheus/style.css";

function Example() {
  const [expanded, setExpanded] = useState(false);
  return (
    <Morpheus
      anchor={MorphAnchor.TopMiddle}
      expanded={expanded}
      onClose={() => setExpanded(false)}
      spring={morphSpringPresets.smooth}
      overlayColor="#0f172a"
      overlayOpacity={0.18}
      overlayBlur={3}
      overlayZIndex={1200}
      viewportPadding={16}
      collapsedContent={
        <button onClick={() => setExpanded(true)}>Open menu</button>
      }
      expandedContent={
        <section>
          <h2>San Francisco</h2>
          <p>Context, actions, and details live here.</p>
          <button onClick={() => setExpanded(false)}>Close</button>
        </section>
      }
    />
  );
}

Morpheus measures the first HTML element of each content prop and animates geometry (width, height, anchored position), surface styles (background color, border color, border width, border radius), and content (opacity, position, uniform scale). For audio cues, pass openSound and closeSound with any of the 16 Cuelume SoundName values such as bloom or droplet; sound is opt-in and the initial render is silent.

Documented limitations: border style is copied from each endpoint and switches rather than interpolating smoothly, and properties such as box shadow, filter, typography, margin, and padding are not independently interpolated. When the destination's natural size exceeds the available viewport, the shell is clamped by viewportPadding (default 16) and becomes scrollable after the opening animation settles. The collapsed source must keep its natural size so Morpheus can measure it, and responsive width rules should live on className. Released under the MIT License.