remold/ui

Morph

Morphs everything inside it whenever its trigger changes.

brand-guidelines.pdf4.2 MB3 days ago
hero-shot.png2.8 MBYesterday
launch-teaser.mp448.1 MB6 days ago
pricing-notes.md100 KB2 days ago
roadmap-q3.pdf1.3 MB12 days ago
team-photo.jpg3.6 MB9 days ago

Installation

npm install @remold-ui/react

Using plain JavaScript? Install @remold-ui/dom instead.

Usage

import { Remold } from "@remold-ui/react";

<Remold.Morph trigger={view}>
  {/* anything that changes when `view` does */}
</Remold.Morph>;

trigger is any value that changes when the content does: a view, a sort order, a route. Morph reads the page during the render in which it changes and animates after React commits, so it works with any state library. It renders a div.

Without React, call transition with the element and a function that changes it. It reads the page, runs the change, and animates what moved. The options below are the same.

When more than one thing can change, pass them as a list. It's compared item by item, like an effect's dependencies, so a new array with the same items doesn't animate:

<Remold.Morph trigger={[view, sort, filter]}>

Examples

Different markup for each view

The grid and the list below are rendered by different elements. Remold pairs each person by what they show, not by where they sit in the tree.

Adjoa TettehDesign
Kwabena FrimpongEngineering
Chloé MartinProduct
Selorm AgbekoEngineering
<Remold.Morph trigger={view}>
  {view === "Grid" ? (
    <PeopleGrid people={people} />
  ) : (
    <PeopleList people={people} />
  )}
</Remold.Morph>

Components from other libraries

To animate a component you don't render yourself, like a Base UI or MUI part, use useRemoldMorph. It takes the same trigger and options as Remold.Morph, and gives you a ref to put on any component that forwards it to its element. Base UI and MUI components both do.

Pro

$24/ month

Billed every month

  • Unlimited projects
  • Version history
  • Priority support
import { useRemoldMorph } from "@remold-ui/react";

const { ref, animating } = useRemoldMorph(billing);

<Tabs.Root ref={ref} value={billing} onValueChange={setBilling}>
  …
</Tabs.Root>;

Without React there's nothing to forward: pass the library's own element to transition.

A few things to know when you use it with component libraries:

  • Portals aren't included. Popovers, menus, selects and dialogs usually render into document.body, outside the element with the ref, so Remold doesn't see them.
  • Turn off the library's own transitions inside the animated area (MUI's Collapse and Fade, Base UI's data-starting-style styles). Remold skips elements at zero opacity, so an element that's still fading in won't be matched.
  • Skip decoration that isn't content, such as MUI's ripple, by wrapping it in <Remold.Ignore> or adding data-rm-ignore.

Choreography

By default everything moves at once. With choreography, a change plays in beats instead: what leaves goes first, then what moves, then what arrives, one after another in reading order. Each part gets out of the way of the next, so the change is easier to follow.

<Remold.Morph trigger={query} choreography>

Pass an object to change the timing, in seconds:

OptionDefault
move0.06How long moves wait once something starts leaving. Only applies when something leaves.
enter0.1How long arrivals wait after moves start. Only applies when something moves.
stagger0.03The gap between one arrival and the next.
maxStagger0.24The longest the whole stagger may take, so a long list still arrives quickly.

The beats overlap, so a choreographed change takes only a little longer than an unchoreographed one, and it can still be interrupted at any point. With reduced motion, changes fade at once.

Announcing changes

<Remold.Morph trigger={sort} announce={(summary) => `Sorted. ${summary.moved} files moved.`}>

API reference

Prop

Type

Data attributes

AttributeMeaning
data-rm-animatingPresent while a transition is running.

On this page