webdevpuneet.com

GSAP Draggable Inertia — Free Momentum Drag & Snap Snippet

GSAP Draggable Inertia · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="di-wrap">
  <div class="di-stage" id="diStage">
    <div class="di-token" id="diToken">Drag me</div>
  </div>
  <p class="di-hint">Flick the token — it keeps moving with momentum, then eases to a stop inside the bounds.</p>
</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

Real momentum
InertiaPlugin continues motion from release velocity.
Bounded stage
Drag and coast both stay inside #diStage.
Edge resistance
Soft push-back near the boundary while dragging.
Unified pointer handling
Mouse, touch, and pen all work identically.
Grab feedback
Scale and shadow shift on drag start and end.
No manual physics
No velocity tracking or animation loop to write.
touch-action: none
Prevents scroll hijacking the drag on mobile.
Single Draggable.create call
One declarative config drives the whole interaction.

About this UI Snippet

GSAP Draggable Inertia — Flick-and-Coast Dragging With Bounded Momentum

Screenshot of the GSAP Draggable Inertia snippet rendered live

The GSAP Draggable Inertia snippet is the difference between a drag interaction that feels mechanical and one that feels physical — release the token mid-flick and it keeps traveling in the direction and speed you threw it, decelerating naturally instead of stopping dead the instant your pointer lifts. It's built with GSAP's Draggable utility plus the InertiaPlugin, loaded from a CDN, and a single bounded stage element.

Draggable does the pointer work

Draggable.create('#diToken', { type: 'x,y', bounds: '#diStage', ... }) hands off all the pointer and touch tracking — mouse, touch, and pen input are normalized into one API, so the token drags smoothly across desktop and mobile without you writing a single pointermove listener. type: 'x,y' lets it move freely in both axes.

Inertia is the momentum

Setting inertia: true (with InertiaPlugin registered) is what turns a plain drag into a throw. When you release the token while it's still moving, GSAP calculates its velocity at release and continues the motion, decaying it smoothly to zero rather than an abrupt stop — the same feel as flicking a card across a table.

Bounds keep it honest

bounds: '#diStage' constrains both the drag and the inertial coast to the stage element, and edgeResistance: 0.65 adds resistance as the token nears the edge during an active drag, so it feels like it's pushing against a soft wall rather than hitting a hard stop. The coast phase respects the same bounds, so a hard flick toward the edge settles just inside it instead of overshooting.

Feedback on grab and release

onDragStart and onDragEnd callbacks scale the token up slightly and deepen its shadow while held, then relax it back — a small tactile cue that reinforces the drag without interfering with Draggable's own transform handling.

Customizing it

Swap type: 'x,y' for 'x' or 'y' to constrain to one axis, tune edgeResistance for a softer or firmer edge feel, or add onThrowComplete to react once the coast finishes. Pair it with a drag sort list or drag throw notes for a board of independently-flickable items.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap, Draggable, and InertiaPlugin from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSA bounded stage with one draggable token renders.
  3. 3
    Drag the tokenIt follows the pointer and resists near the edges.
  4. 4
    Flick and releaseIt keeps coasting with momentum, then eases to a stop.
  5. 5
    Try a slow drag and releaseWith little velocity, it stops close to where you let go.
  6. 6
    Adjust bounds or resistanceChange #diStage or edgeResistance to retune the feel.

Real-world uses

Common Use Cases

Sortable board momentum
Add physical feel to a drag sort list, where a flick continues in the release direction and decelerates smoothly.
Sticky note walls
Give notes a similar feel to drag-throw notes, staying inside the stage with soft edge resistance.
Onboarding demos
Show a flingable token beside a bento grid, where mouse, touch and pen all behave identically.
Throwable kanban cards
Add throwable motion to a card on a kanban board, with bounds keeping it within the board once it stops.
Casual game pieces
Reuse the release-velocity physics for casual game pieces or a floating panel that users can fling to a screen corner.
Related: Morphing Icon State Transitions (Play/Pause, Bookmark, Menu/Close)
See the Morphing Icon State Transitions (Play/Pause, Bookmark, Menu/Close) for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Plain Draggable stops the element exactly where the pointer releases it. InertiaPlugin calculates the element's velocity at the moment of release and continues its motion, decelerating it smoothly to zero — that's what produces the throw-and-coast feel instead of an abrupt stop.

InertiaPlugin is a Club GreenSock bonus plugin. Recent versions of the public gsap npm/CDN package have bundled it for no-signup use in many contexts, but licensing terms can change and commercial use may require a Club GreenSock membership depending on your use case — check GreenSock's current licensing page before shipping this in a commercial product.

Yes. bounds: '#diStage' constrains both the active drag and the inertial coast, so a hard flick toward an edge decelerates and settles just inside the boundary rather than flying out of the stage.

Yes. Draggable normalizes mouse, touch, and pen input into one API, and touch-action: none on the token stops the browser from interpreting the drag as a page scroll, so flicks register cleanly on mobile.

Render the stage and token, then in a mount effect register Draggable and InertiaPlugin and call Draggable.create scoped to the container. Store the returned Draggable instance and call .kill() in the cleanup function to avoid duplicate instances on re-render or unmount.