iOS App Store: Layout animation

Matt Perry
In this tutorial, we're going to build the iOS App Store: Layout animation example step-by-step.
This example is rated advanced difficulty, which means we assume you're already quite familiar with Motion (and JavaScript in general).
Here's a live demo of the example we're going to be creating:
Introduction
The iOS App Store example recreates the card expand/collapse animation seen in Apple's App Store. When you click a card, it smoothly expands into a full-screen modal with additional content visible. Clicking outside the modal or pressing Escape closes it with the reverse animation.
This tutorial uses the animateLayout function from Motion+. This function automatically animates elements between layout states using the FLIP technique. By adding data-layout-id attributes to elements, Motion tracks their positions before and after a DOM change, then animates the difference.
Get started
Let's build the card grid layout with some sample content cards. The key is adding data-layout-id attributes to elements we want to animate:
Each element that should animate has a unique data-layout-id. When the same ID exists in both the source and destination layouts, Motion animates between them.
The data-layout attribute controls how elements animate:
preserve-aspect- Maintains the element's aspect ratio during the animation (used for images)position- Only animates position, not size (used for the title container)
Let's animate!
Import from Motion
First, import the animateLayout function from Motion+ and animate for the overlay:
Set up state tracking
We need to track the animation state and which card is currently open:
Define the transition
Create a shared transition configuration:
This uses a custom cubic bezier easing curve that gives the animation a natural, iOS-like feel.
Create a layout animation wrapper
This helper function manages the layout animation lifecycle, ensuring only one animation runs at a time:
The animateLayout function:
Snapshots the current position of all elements with
data-layout-idRuns the callback function (which modifies the DOM)
Measures the new positions
Animates from the old positions to the new positions
Add click handlers to cards
Set up click handlers on each card:
When a card is clicked, we call startLayoutAnimation with a callback that opens the card. The animateLayout function handles all the animation automatically based on the data-layout-id attributes.
Create the open card function
The openCard function creates the expanded modal version of the card:
This function clones the clicked card's content and places it in a fixed-position container. Because the cloned elements have the same data-layout-id values as the source, animateLayout automatically animates from the card position to the modal position.
Handle the overlay
The overlay fades in and out separately from the layout animation:
Add the close animation
Create a function to handle closing the modal:
The close animation removes the modal from the DOM inside the animateLayout callback. Motion automatically animates the elements back to their original positions in the card grid.
Implement the close card function
Add the cleanup function that removes the modal:
Add keyboard support
Finally, add support for closing the modal with the Escape key:
Conclusion
We've built a polished card-to-modal interface using Motion's animateLayout function. By adding data-layout-id attributes to elements, Motion automatically tracks and animates layout changes. The data-layout attribute gives fine-grained control over how individual elements animate - preserving aspect ratios for images and animating only position for text. This declarative approach makes complex shared-element transitions straightforward to implement.


