โ† Back
Morphing Animations with Motion

Morphing Animations with Motion

How to use morphing animations with Motion to make UI state changes clearer instead of noisier.

ยทmotionanimationmorphingmotion designreactuiinteraction design

We are in a strange phase of the web.

For a few years, everything was flat, quiet, and minimal. Fashion, product design, websites, all pushing in the same direction: less color, less texture, less motion. That phase is fading. Interfaces are getting richer again, and you can feel it everywhere, from app onboarding to landing pages to the OS itself.

At the same time, most of the limits that used to keep us honest are gone. Hardware is fast. Browsers can render complex scenes easily. Animation libraries like Motion got good enough that things which used to take a week now take an afternoon.

Put those two things together and the result is predictable. More ambition, more layers, and a lot more animation on screen.

When animation is used well, it gives life to an interface. Interactions feel clearer, products feel more polished, and the user gets a feel for the app without having to think about it.

When it is used poorly, it does the opposite. It turns the product into a toy.

This is not really a post about animation. It is a post about how we use the tools we have. The same library can produce something clean and sharp, or something noisy and confusing. The library does not decide. We do.

This basic demo shows the main idea. The button changes label, icon, color, and width, but it still feels like the same control going from idle to working to done.

Live Demo

The Point

In product work, I want animation to do at least one of these:

  • Show feedback. Something happened because the user did something.
  • Keep context. One screen, card, or panel turned into another.
  • Clarify hierarchy. Show that this matters more than that.
  • Explain flow. The user can follow the state change without effort.

If it is not doing any of that, I cut it.

Morphing is one of the best patterns for this. It does two jobs at once. It shows that something happened, and it shows how two states are related, so the user does not have to piece that together on their own.

Morphing is when one element turns into another in a way that still feels like the same thing.

That last part is the whole point. The user should feel that it is the same thing, not a replacement.

When a compact player expands into a full player, or a pill button opens into a picker, the user should feel:

this thing became that thing

not:

one thing disappeared and another thing showed up

The difference is small in code, but big in how the UI feels.

Why It Works

Morphing is not just a visual style. It works because of how we see change.

When a shape changes smoothly, we read it as the same thing becoming something new. When a shape disappears and a different one shows up nearby, we read them as two separate things, even if they look almost the same. It is the same instinct that lets you follow a coin under three cups.

A morph in a UI uses that instinct. When a button expands into a panel, the user does not have to reconnect the two states in their head. They already feel like the same thing because they were never separate to begin with.

That is why morphing is worth the extra effort. It moves work out of the user's head and into the interface.

A cut or a crossfade does not do that. It hands the user two screens and asks them to figure out the relationship. A good morph makes the relationship obvious.

The Anatomy of a Morph

Most morphs have three layers, and it helps to think about them separately when you build one.

  • The shell. The outer container that changes size, shape, or position. This carries the identity of the component.
  • The anchors. One or two elements that stay visually the same across both states. They are the "this is still me" signals.
  • The content. Everything that is unique to each state. This is what fades, slides, or reorders.

If the shell morph feels off, nothing else will save it. If the anchors are missing, the user reads two unrelated components instead of one. If too much content moves at the same time, the eye loses track of what to follow.

Most bad morphs fail for the same reason. Everything moves at once. Pick the layer that matters most, let it lead, and let the rest follow.

A good morph is almost invisible. The user notices that the UI changed, not that something animated.

When To Use It

Before I use morphing, I check three things:

  • Are these two states clearly part of the same interaction?
  • Does the user benefit from seeing the relationship?
  • Is the transition making the UI clearer, not just more impressive?

If the answer is no to any of them, I use something simpler.

Morphing is not a default. If every element on the page tries to morph into something else, the interface starts to feel too dramatic.

Why Motion Works Well

I use Motion for this kind of work because it handles the hard part: keeping the same feel between states without making me plan every pixel by hand.

There are two common cases. Sometimes the same DOM element changes shape or size. Other times, one rendered tree turns into a different one. The second case is where shared layout really helps.

<motion.div layoutId="card" />

With a shared layoutId, Motion treats two separate elements as the same visual thing across states.

A few things you get for free:

  • Position and size animate together instead of snapping.
  • Border radius and spacing changes feel connected.
  • Entering and exiting content can sit on top of the shell transition.
  • You do not have to hand roll FLIP logic for every case.

You end up with less code and fewer odd edge cases. It also makes it easier to build the transition in the right order:

  1. Get the shell morph right.
  2. Animate the important child elements.
  3. Add small enter or exit details, but only if they actually help.

If the shell feels wrong, adding more animation just makes the problem louder.

Example 1: A Feedback Form

This one is intentionally simple. A compact prompt grows into a small form.

The motion is doing real UI work:

  • The container expands instead of being replaced.
  • The label shifts position instead of vanishing and reappearing.
  • The textarea and actions fade in after the shell has already opened.

First the surface opens, then the controls show up. That order keeps it readable.

Live Demo

Example 2: A Reaction Picker

This one uses shared layout between two different UI trees. That is the right approach when the collapsed and expanded states are built differently. The closed state is a summary chip. The open state is a small picker panel. They do not share the same inner layout, but they do share a visual identity.

The anchors are the outer shell, the reaction badge, and the title block. Those are what tell the eye that the chip and the panel are the same thing in different forms, while everything else changes around them.

Live Demo

Example 3: A Compact Music Player

This is the most complete example because it combines several layers:

  • A shell morph from mini player to full player
  • Shared artwork, title, and play button
  • Secondary content that reveals after the shell has expanded
  • An independent playback animation that keeps running across states

That is what makes it feel like one player instead of two separate widgets.

The slow mode toggle is useful because it exposes the structure. If an animation only looks good at full speed, it is usually hiding something sloppy.

Live Demo

A Few Practical Rules

After building a lot of these, my rules are short:

  • Morph between related states, not unrelated components.
  • Keep one or two strong identity anchors and let everything else move around them.
  • Animate the shell first, then the inner details.
  • Use spring motion for physical UI changes, but keep it tight.
  • Let secondary content arrive slightly later when that helps clarity.
  • Cut anything that makes the interaction harder to read.

The biggest mistake is treating morphing as a visual trick. It is not a flourish. It is a way to explain a state change so the user does not have to.