gsap-flip-layout

Installation
SKILL.md

GSAP Flip

When to use this

  • A DOM mutation (class toggle, reparenting, reordering, filtering) changes an element's position or size and you want the change to animate instead of snapping.
  • You need a "shared element transition" feel: a thumbnail that becomes a full detail view, a card that moves from one list to another, without manually computing the delta transform yourself.
  • You're toggling between two distinct layouts (grid/list view, sidebar collapse/expand, responsive reflow) and every affected element should smoothly reflow together.
  • You need this to work for elements that move across different DOM parents, not just elements that stay in place and resize.
  • Do NOT use this when the animation is a simple property tween with no layout/DOM-structure change involved (use gsap-core-timelines), or when the trigger is scroll position rather than a discrete state change (use gsap-scrolltrigger).

Mental model

Flip stands for First, Last, Invert, Play, and it names the actual four-step algorithm, not just a plugin brand. "First" is Flip.getState(targets), called before you make any DOM/class change: it measures and records the current bounding box (position, size) and optionally other properties of every matched element. You then make the actual layout-changing mutation however you normally would (toggle a class, move a node with appendChild, change a CSS grid, whatever), which causes the browser to lay elements out at their new ("Last") positions instantly with no animation. Flip.from(state, vars) is the Invert+Play step combined: it re-measures the new position, computes the delta between First and Last as a transform, applies that transform to make the element instantly appear back at its OLD position (Invert, using CSS transform so it is cheap), and then animates the transform to zero (Play), which visually reads as the element moving smoothly from old to new.

This is why Flip does not need to know anything about layout systems (flexbox, grid, absolute positioning) or your specific CSS: it only ever deals in "the element used to occupy this rectangle, now it occupies that rectangle," and bridges the two with a transform-based tween. It works across reparenting because getState records position in a layout-independent way (effectively viewport-relative or a stable reference frame) and the invert step does not care which DOM parent currently owns the node, only where it visually sits.

For elements whose intrinsic size also changes (not just position), Flip by default scales via transform: scale() during the animated portion and un-scales at the end, so text/borders do not stay stretched during the transition. When absolute: true is passed, Flip temporarily takes the animating elements out of document flow (position: absolute) for the duration of the animation, which is essential when the "First" and "Last" layouts have a different number of elements or different flow behavior that would otherwise cause other elements to jump around while the flip animation is still playing; it restores normal flow after the animation completes.

Nested Flip (a Flip animation on a parent that also contains child elements with their own layout changes) works by capturing state for both parent and children in the same getState call (pass a broad enough selector) so that the delta computation and inversion accounts for all of them together, avoiding double-compensation where a child's position looks wrong because the parent already moved.

Installs
2
First Seen
Aug 30, 2026
gsap-flip-layout — avnehsbhatia/ultraui