webdevpuneet.com

GSAP Flip Layout Transition — Free Grid/List Reorder Snippet

GSAP Flip Layout Transition · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="fl-wrap">
  <div class="fl-bar">
    <button class="fl-btn is-active" data-view="grid">Grid</button>
    <button class="fl-btn" data-view="list">List</button>
    <button class="fl-btn fl-shuffle" data-action="shuffle">Shuffle</button>
  </div>
  <div class="fl-board" id="flBoard">
    <div class="fl-card" data-id="1"><span class="fl-num">01</span><h3>Nova</h3></div>
    <div class="fl-card" data-id="2"><span class="fl-num">02</span><h3>Ridge</h3></div>
    <div class="fl-card" data-id="3"><span class="fl-num">03</span><h3>Ember</h3></div>
    <div class="fl-card" data-id="4"><span class="fl-num">04</span><h3>Lumen</h3></div>
    <div class="fl-card" data-id="5"><span class="fl-num">05</span><h3>Cove</h3></div>
    <div class="fl-card" data-id="6"><span class="fl-num">06</span><h3>Drift</h3></div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Grid/list morph
Toggle layouts with a single animated transition.
Shuffle reorder
Cards animate to their new sorted position.
One shared helper
runFlip wraps getState, mutate, and Flip.from.
Staggered reflow
Cards don't move as one rigid block.
Absolute positioning
Cards can cross paths without fighting layout.
Double-click guard
Active view button ignores redundant clicks.
CSS drives layout
Flip reads real computed positions, not hardcoded ones.
Reusable pattern
Any DOM mutation can be wrapped the same way.

About this UI Snippet

GSAP Flip Layout Transition — Smoothly Morph Between Layouts

Screenshot of the GSAP Flip Layout Transition snippet rendered live

The GSAP Flip layout transition snippet solves a problem that's genuinely hard to animate by hand: when a layout changes — grid to list, or cards reordering — every element's position and size changes at once, and animating that manually means calculating deltas yourself. GSAP's Flip plugin (First, Last, Invert, Play) does it for you, loaded from a CDN alongside GSAP core.

Capture, mutate, animate

The pattern is three steps, wrapped in one runFlip helper. First, Flip.getState('#flBoard .fl-card') records the current position and size ("First") of every card. Then the DOM mutation runs — toggling the is-list class or reordering the cards — which jumps the layout to its new state ("Last") instantly, with no visible animation. Finally Flip.from(state, ...) compares the recorded state to the new layout, inverts each card back to where it used to be, and plays it forward to its new position — the actual "Play" step, all handled internally.

Two very different triggers, one helper

Both the grid/list toggle and the shuffle button call the same runFlip function with a different mutation callback. That's the point of Flip: it doesn't care why the layout changed — a class toggle, a re-sort, or a filter — it just diffs before and after and animates the gap. Any DOM change that alters position, size, or existence of matched elements can be Flipped this way.

Options that shape the feel

stagger: 0.03 offsets each card's animation slightly so a full-board reflow doesn't move as one rigid block. absolute: true temporarily takes cards out of flow during the animation so they can cross over each other without fighting the grid's own reflow. ease: 'power2.inOut' gives the motion a smooth accelerate-decelerate curve appropriate for a layout shift rather than an entrance.

Preventing double-clicks

The view buttons guard against re-triggering on the already-active view (if (btn.classList.contains('is-active')) return), so clicking Grid while already in grid view doesn't run a no-op Flip.

Customizing it

Add more layout variants (masonry, single column), animate additions/removals with Flip.fit or the onEnter/onLeave callbacks, or combine it with a filter UI. Pair it with a drag sort list or bento grid for a fuller layout toolkit.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap and Flip from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSA card board with Grid/List/Shuffle controls renders.
  3. 3
    Click ListCards smoothly morph from a grid into a stacked list.
  4. 4
    Click GridThey morph back, animated the same way.
  5. 5
    Click ShuffleCards reorder and animate from old to new position.
  6. 6
    Resize the windowLayout stays responsive; the next Flip still works.

Real-world uses

Common Use Cases

Grid and list view switchers
Toggle layouts like a bento grid with a single animated transition, wrapping getState, mutate and Flip.from in one helper.
Sortable board reorders
Animate cards to their new sorted position alongside a drag sort list, so a reorder never jumps.
Kanban card movement
Morph card positions when they change column in a kanban board, with a stagger so cards do not move as one rigid block.
Filterable gallery reflows
Reflow a filtered grid without a hard jump, since GSAP Flip measures before and after positions for every element.
Dashboard widget resizing
Animate widget reflow when a panel is resized or hidden, so neighbouring tiles glide into their new places.
Related: Motion Path Plane
See the Motion Path Plane for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Flip doesn't animate properties you specify — it animates the difference between two DOM states it measures itself. Flip.getState captures each element's position and size before a change; after your mutation runs, Flip.from measures the new layout and animates every matched element from its old bounding box to its new one.

Flip.getState must run while the layout is still in its original arrangement, so it has something to diff against. The mutation (toggling a class, reordering nodes) then happens instantly with no animation, and Flip.from immediately inverts the visual result back to the recorded start state and animates it forward — that's what makes the transition look continuous.

Without it, cards animating to new positions can be shoved around by the CSS grid's own live reflow while mid-transition, especially when several cards cross paths during a shuffle. absolute: true temporarily takes matched elements out of normal flow for the duration of the Flip so they can move freely and settle into their final grid position.

Flip supports that too, via onEnter and onLeave callbacks passed to Flip.from, which let you animate newly-added or about-to-be-removed elements separately from the ones simply changing position. This snippet only covers reorder and layout-class changes, but the same getState/mutate/Flip.from pattern extends to insertions and removals.

Call Flip.getState before you update the state that drives the DOM change (e.g. before setState), let the framework re-render, then call Flip.from in a layout effect that runs after the DOM update. In React, useLayoutEffect is the right place; keep the getState snapshot in a ref so it survives the render.