Skip to content

LayoutMorph Plugin

LayoutMorph is a FLIP (First, Last, Invert, Play) animation plugin. It seamlessly animates elements between two completely different states in the DOM.

Click to advance tour
Welcome back
Alex Morgan
+ New Project
Monthly Revenue ↑ 12%
$24,500
Active Users ↑ 4%
1,284
Activity Overview
60 FPS

The three-step pattern

Animating a layout shift always follows the exact same three steps:

  1. Capture the current state of the elements using LayoutMorph.record().
  2. Modify the DOM instantly (change classes, move elements, change flex-direction).
  3. Animate from the captured state using LayoutMorph.play().
Click to trigger basic morph
60 FPS

Automatic edge cases

LayoutMorph automatically un-projects and preserves complex layout states without requiring manual configuration:

  • Native Transforms: If an element is already rotated or skewed, LayoutMorph preserves that matrix independently of layout translations.
  • Border radius & width: When elements stretch or squash, their borders usually warp. LayoutMorph automatically applies inverse-scaling so strokes don't stretch horizontally or vertically.
  • Opacity: It auto-detects fade state changes and tweens opacity alongside layout geometries.
Click to morph 3D isometric card
60 FPS

Configuration API

Configuration objects can be passed to both record() and play() to control the behavior of the layout shift.

props - tracking CSS properties

By default, LayoutMorph tracks position and dimensions (x, y, scaleX, scaleY, rotation, skewX, and opacity). To animate standard CSS properties alongside the layout shift, declare them in the record config.

Click to toggle tracked props
60 FPS

stagger - cascading animations

An array of elements or a NodeList can be passed to track entire component lists. Similar to regular tweens, the standard stagger timeline property is supported in play() to orchestrate cascading reflows.

Click to trigger staggered list reflow
60 FPS

absolute: true - out-of-flow optimization

Normally, when elements animate across the screen, their physical bodies still take space in the layout. When rearranging a complex grid or flex container, moving bodies can displace sibling elements, causing the layout to jitter during the transition.

Setting absolute: true temporarily removes the elements from the normal page structure, allowing them to float without breaking the grid during movement. Upon animation completion, they instantly snap back into native document flow.

Click to trigger absolute wrap flow
60 FPS

nested: true - inverse scale correction

When a parent container scales up, all its children naturally stretch with it. Tracking a parent and a child simultaneously creates compound matrix scaling that causes the child to "double-scale".

Pass nested: true to both methods to instruct the engine to continuously invert the parent's scale matrix against the child, keeping them geometrically synced.

Click to execute nested scale inverse
60 FPS

Utility methods

LayoutMorph.fit(source, target)

Calculates and executes a layout bridge between two distinct DOM nodes, translating and scaling the source element to perfectly encompass the target element's bounding box.

Click to fit bounds
60 FPS

Timeline integration

play() returns a standard AnimX.Timeline instance. This allows subsequent procedural animations to be chained natively using standard .add() or .animate() methods immediately following layout convergence.

Click to evaluate timeline chain
60 FPS

Real-world composition

Combining absolute: true with tracked NodeLists allows for extremely complex native CSS property swaps (such as entirely replacing display: grid with display: flex) while maintaining 60fps tracking arrays.

Click to execute structure swap
60 FPS

API Reference

Importing

Via NPM (Bundlers):

js
import { LayoutMorph } from 'animx/plugins/LayoutMorph';

Via CDN (Global):

js
// AnimX is exposed globally, plugins are attached automatically
const tl = AnimX.LayoutMorph.play(...)

Methods

MethodDescription
record(targets, props?)Records the bounding boxes and visual styles (opacity, rotation, etc.) of target elements. Returns an opaque state object.
play(state, config?)Calculates difference from recorded state and instantly animates elements from old to new bounds. Returns a Timeline.
fit(source, target, config?)Animates the source element to perfectly encompass the exact physical bounding box of the target element. Returns a Tween.

Configuration Options

Both play() and fit() accept an extended tween config object. Along with standard tween properties (duration, ease, delay), it supports:

PropertyTypeDefaultDescription
absolutebooleanfalseForces elements to position: absolute during animation. Vital for structural DOM swaps.
nestedbooleanfalseEnables scale-correction for nested morphing children.
staggernumber0Stagger time in seconds between each element if animating a list.
onStartFunctionnullCallback fired when the FLIP animation begins.
onCompleteFunctionnullCallback fired when the FLIP animation finishes and native layout is restored.