# Table of Contents
- [docsHome | GSAP | Docs & Learning](#docshome-gsap-docs-learning)
- [Flip | GSAP | Docs & Learning](#flip-gsap-docs-learning)
- [GSAP | GSAP | Docs & Learning](#gsap-gsap-docs-learning)
- [HelperFunctions | GSAP | Docs & Learning](#helperfunctions-gsap-docs-learning)
- [CSSRule | GSAP | Docs & Learning](#cssrule-gsap-docs-learning)
- [Installation | GSAP | Docs & Learning](#installation-gsap-docs-learning)
- [Tween | GSAP | Docs & Learning](#tween-gsap-docs-learning)
- [CSS | GSAP | Docs & Learning](#css-gsap-docs-learning)
- [SteppedEase | GSAP | Docs & Learning](#steppedease-gsap-docs-learning)
- [Easing | GSAP | Docs & Learning](#easing-gsap-docs-learning)
- [ScrollSmoother | GSAP | Docs & Learning](#scrollsmoother-gsap-docs-learning)
- [Timeline | GSAP | Docs & Learning](#timeline-gsap-docs-learning)
- [checkPrefix | GSAP | Docs & Learning](#checkprefix-gsap-docs-learning)
- [Attributes | GSAP | Docs & Learning](#attributes-gsap-docs-learning)
- [Utility Methods | GSAP | Docs & Learning](#utility-methods-gsap-docs-learning)
- [Draggable | GSAP | Docs & Learning](#draggable-gsap-docs-learning)
- [ScrollTrigger | GSAP | Docs & Learning](#scrolltrigger-gsap-docs-learning)
- [Snap | GSAP | Docs & Learning](#snap-gsap-docs-learning)
- [gsap.context() | GSAP | Docs & Learning](#gsap-context-gsap-docs-learning)
- [Modifiers | GSAP | Docs & Learning](#modifiers-gsap-docs-learning)
- [EndArray | GSAP | Docs & Learning](#endarray-gsap-docs-learning)
- [clamp | GSAP | Docs & Learning](#clamp-gsap-docs-learning)
- [getUnit | GSAP | Docs & Learning](#getunit-gsap-docs-learning)
- [distribute | GSAP | Docs & Learning](#distribute-gsap-docs-learning)
- [MorphSVG | GSAP | Docs & Learning](#morphsvg-gsap-docs-learning)
- [gsap.ticker() | GSAP | Docs & Learning](#gsap-ticker-gsap-docs-learning)
- [gsap.matchMedia() | GSAP | Docs & Learning](#gsap-matchmedia-gsap-docs-learning)
- [interpolate | GSAP | Docs & Learning](#interpolate-gsap-docs-learning)
- [shuffle | GSAP | Docs & Learning](#shuffle-gsap-docs-learning)
- [toArray | GSAP | Docs & Learning](#toarray-gsap-docs-learning)
- [pipe | GSAP | Docs & Learning](#pipe-gsap-docs-learning)
- [unitize | GSAP | Docs & Learning](#unitize-gsap-docs-learning)
- [mapRange | GSAP | Docs & Learning](#maprange-gsap-docs-learning)
- [normalize | GSAP | Docs & Learning](#normalize-gsap-docs-learning)
- [wrap | GSAP | Docs & Learning](#wrap-gsap-docs-learning)
- [random | GSAP | Docs & Learning](#random-gsap-docs-learning)
- [selector | GSAP | Docs & Learning](#selector-gsap-docs-learning)
- [wrapYoyo | GSAP | Docs & Learning](#wrapyoyo-gsap-docs-learning)
- [splitColor | GSAP | Docs & Learning](#splitcolor-gsap-docs-learning)
- [snap | GSAP | Docs & Learning](#snap-gsap-docs-learning)
- [Easel | GSAP | Docs & Learning](#easel-gsap-docs-learning)
- [MotionPath | GSAP | Docs & Learning](#motionpath-gsap-docs-learning)
- [ScrollTo | GSAP | Docs & Learning](#scrollto-gsap-docs-learning)
- [RoughEase | GSAP | Docs & Learning](#roughease-gsap-docs-learning)
- [Text | GSAP | Docs & Learning](#text-gsap-docs-learning)
- [SlowMo | GSAP | Docs & Learning](#slowmo-gsap-docs-learning)
- [ExpoScaleEase | GSAP | Docs & Learning](#exposcaleease-gsap-docs-learning)
- [CustomEase | GSAP | Docs & Learning](#customease-gsap-docs-learning)
- [Physics2D | GSAP | Docs & Learning](#physics2d-gsap-docs-learning)
- [DrawSVG | GSAP | Docs & Learning](#drawsvg-gsap-docs-learning)
- [ScrambleText | GSAP | Docs & Learning](#scrambletext-gsap-docs-learning)
- [CustomWiggle | GSAP | Docs & Learning](#customwiggle-gsap-docs-learning)
- [PhysicsProps | GSAP | Docs & Learning](#physicsprops-gsap-docs-learning)
- [CustomBounce | GSAP | Docs & Learning](#custombounce-gsap-docs-learning)
- [Plugins | GSAP | Docs & Learning](#plugins-gsap-docs-learning)
- [nestedLinesSplit | GSAP | Docs & Learning](#nestedlinessplit-gsap-docs-learning)
- [progressiveBuild | GSAP | Docs & Learning](#progressivebuild-gsap-docs-learning)
- [globalTime | GSAP | Docs & Learning](#globaltime-gsap-docs-learning)
- [getChildren | GSAP | Docs & Learning](#getchildren-gsap-docs-learning)
- [resume | GSAP | Docs & Learning](#resume-gsap-docs-learning)
- [pluckRandomFrom | GSAP | Docs & Learning](#pluckrandomfrom-gsap-docs-learning)
- [pointerEvent | GSAP | Docs & Learning](#pointerevent-gsap-docs-learning)
- [getTweensOf | GSAP | Docs & Learning](#gettweensof-gsap-docs-learning)
- [restart | GSAP | Docs & Learning](#restart-gsap-docs-learning)
- [smoothOriginChange | GSAP | Docs & Learning](#smoothoriginchange-gsap-docs-learning)
- [seek | GSAP | Docs & Learning](#seek-gsap-docs-learning)
- [reverse | GSAP | Docs & Learning](#reverse-gsap-docs-learning)
- [disable | GSAP | Docs & Learning](#disable-gsap-docs-learning)
- [invalidate | GSAP | Docs & Learning](#invalidate-gsap-docs-learning)
- [trackDirection | GSAP | Docs & Learning](#trackdirection-gsap-docs-learning)
- [iteration | GSAP | Docs & Learning](#iteration-gsap-docs-learning)
- [isActive | GSAP | Docs & Learning](#isactive-gsap-docs-learning)
- [tickGSAPWhileHidden | GSAP | Docs & Learning](#tickgsapwhilehidden-gsap-docs-learning)
- [time | GSAP | Docs & Learning](#time-gsap-docs-learning)
- [kill | GSAP | Docs & Learning](#kill-gsap-docs-learning)
---
# docsHome | GSAP | Docs & Learning
[Skip to main content](#__docusaurus_skipToContent_fallback)
A wildly robust JavaScript animation library. Built for professionals
Animate Anything
================
Search
GSAP Overview
-------------
This page provides a comprehensive view of the GSAP ecosystem, outlining which features are part of GSAP's core, which files are hosted on the public CDN, and which are exclusively accessible to [Club GSAP members](https://gsap.com/pricing/)
.
The Core contains **everything** you need to create blazingly fast, responsive animations for all browsers.
Additional capabilities, like [Dragging](/docs/v3/Plugins/Draggable/)
, [Scroll Animation](/docs/v3/Plugins/ScrollTrigger)
or [Morphing](/docs/v3/Plugins/MorphSVGPlugin)
are tucked away in plugins. This allows the core to remain relatively small and lets you add features only when you need them.
Most usage is covered under our [no-charge license](https://gsap.com/community/standard-license/)
, but you will need a commercial license in projects that you sell to multiple end users. [More information on licensing here](https://gsap.com/licensing/)
Included in GSAP's Core
-----------------------
* [GSAP\
----](/docs/v3/GSAP)
CDN
[Tween](/docs/v3/GSAP/Tween)
and [Timeline](/docs/v3/GSAP/Timeline)
### Animate anything
* [CSS properties](/docs/v3/GSAP/CorePlugins/CSS)
* [Attributes](/docs/v3/GSAP/CorePlugins/Attributes)
* [Array Values](/docs/v3/GSAP/CorePlugins/EndArray)
* [and more...](/resources/get-started#any-numeric-value-color-or-complex-string-containing-numbers)
### [Eases](/docs/v3/Eases)
* ["none"](/docs/v3/Eases)
* ["power1"](/docs/v3/Eases)
* ["power2"](/docs/v3/Eases)
* ["power3"](/docs/v3/Eases)
* ["power4"](/docs/v3/Eases)
* ["back"](/docs/v3/Eases)
* ["bounce"](/docs/v3/Eases)
* ["circ"](/docs/v3/Eases)
* ["elastic"](/docs/v3/Eases)
* ["expo"](/docs/v3/Eases)
* ["sine"](/docs/v3/Eases)
* ["steps(n)"](/docs/v3/Eases/SteppedEase)
### Animate efficiently
* [Staggers](/resources/getting-started/Staggers)
* [Callbacks](/resources/getting-started/control#callbacks)
* [Responsive - matchMedia()](/docs/v3/GSAP/gsap.matchMedia())
* [Snapping](/docs/v3/GSAP/CorePlugins/Snap)
* [Modifiers](/docs/v3/GSAP/CorePlugins/Modifiers)
* [Keyframes](/resources/keyframes)
* [Ticker with lag smoothing](/docs/v3/GSAP/gsap.ticker())
* [Cleanup - context() & revert()](/docs/v3/GSAP/gsap.context())
### [Utility Methods](/docs/v3/GSAP/UtilityMethods)
* [checkPrefix()](/docs/v3/GSAP/UtilityMethods/checkPrefix())
* [clamp()](/docs/v3/GSAP/UtilityMethods/clamp())
* [distribute()](/docs/v3/GSAP/UtilityMethods/distribute())
* [getUnit()](/docs/v3/GSAP/UtilityMethods/getUnit())
* [interpolate()](/docs/v3/GSAP/UtilityMethods/interpolate())
* [mapRange()](/docs/v3/GSAP/UtilityMethods/mapRange())
* [normalize()](/docs/v3/GSAP/UtilityMethods/normalize())
* [pipe()](/docs/v3/GSAP/UtilityMethods/pipe())
* [random()](/docs/v3/GSAP/UtilityMethods/random())
* [selector()](/docs/v3/GSAP/UtilityMethods/selector())
* [shuffle()](/docs/v3/GSAP/UtilityMethods/shuffle())
* [snap()](/docs/v3/GSAP/UtilityMethods/snap())
* [splitColor()](/docs/v3/GSAP/UtilityMethods/splitColor())
* [toArray()](/docs/v3/GSAP/UtilityMethods/toArray())
* [unitize()](/docs/v3/GSAP/UtilityMethods/unitize())
* [wrap()](/docs/v3/GSAP/UtilityMethods/wrap())
* [wrapYoyo()](/docs/v3/GSAP/UtilityMethods/wrapYoyo())
Publicly Available
------------------
### [Plugins](/docs/v3/Plugins)
* [Draggable](/docs/v3/Plugins/Draggable)
CDN
* [Easel](/docs/v3/Plugins/EaselPlugin)
CDN
* [Flip](/docs/v3/Plugins/Flip)
CDN
* [MotionPath](/docs/v3/Plugins/MotionPathPlugin)
CDN
* [Observer](/docs/v3/Plugins/Observer)
CDN
* [Pixi](/docs/v3/Plugins/PixiPlugin)
CDN
* [ScrollTo](/docs/v3/Plugins/ScrollToPlugin)
CDN
* [ScrollTriggerpopular](/docs/v3/Plugins/ScrollTrigger)
CDN
* [Text](/docs/v3/Plugins/TextPlugin)
CDN
### Eases
* ["rough()"](/docs/v3/Eases/RoughEase)
["slow()"](/docs/v3/Eases/SlowMo)
["expoScale()"](/docs/v3/Eases/ExpoScaleEase)
CDN
* ["CustomEase()"](/docs/v3/Eases/CustomEase)
CDN
### React React Logo
* [useGSAP()](/resources/React)
npm
Available for Club GSAP members
-------------------------------
### [Club GSAP](https://gsap.com/pricing/)
[](https://gsap.com/pricing/ "plus")
[](https://gsap.com/pricing/ "premium")
[](https://gsap.com/pricing/ "business")
* [DrawSVG](/docs/v3/Plugins/DrawSVGPlugin)
trial
* [Physics2D](/docs/v3/Plugins/Physics2DPlugin)
trial
* [PhysicsProps](/docs/v3/Plugins/PhysicsPropsPlugin)
trial
* [ScrambleText](/docs/v3/Plugins/ScrambleTextPlugin)
trial
* [CustomBounce](/docs/v3/Eases/CustomBounce)
trial
* Requires CustomEase
* [CustomWiggle](/docs/v3/Eases/CustomWiggle)
trial
* Requires CustomEase
* [GSDevTools](/docs/v3/Plugins/GSDevTools)
trial
* [Inertia](/docs/v3/Plugins/InertiaPlugin)
trial
* [MorphSVG](/docs/v3/Plugins/MorphSVGPlugin)
trial
* [MotionPathHelper](/docs/v3/Plugins/MotionPathHelper)
trial
* [ScrollSmoother](/docs/v3/Plugins/ScrollSmoother)
trial
* [SplitText](/docs/v3/Plugins/SplitText)
trial
* * *
* [Commercial license](/licensing)
* * *
[Trial the Club Plugins FREE](https://gsap.com/resources/trial/)
[Sign up today!](https://gsap.com/pricing/)
---
# Flip | GSAP | Docs & Learning
[Skip to main content](#__docusaurus_skipToContent_fallback)
On this page
info
Flip involves a whole different way of thinking about animation. Once you get it, you'll be wowed.
Flip plugin lets you seamlessly transition between two states even if there are sweeping changes to the structure of the DOM that would normally cause elements to jump.
Flip records the current position/size/rotation of your elements, you make whatever changes you want, and then Flip applies offsets to make them **_look_** like they never moved... Lastly FLIP animates the **removal** of those offsets! UI transitions become remarkably simple to code. Flip does all the heavy lifting.
What people are saying:
-----------------------
> _Experimenting more with GSAP's flip plugin and I'm blown away by how much this accelerates development! What a powerful tool!_💪_"_ - Manoela Ilic, Codrops
> _"HOW DOES IT KNOW WHAT TO DO?_ 🤯_"_ - @georgedoescode
> _"I'm truly amazed at the power of GSAP and FLIP."_ - @Alex.Marti
> _"My 'Wow' of the week goes to the Flip Plugin. Star-struck. It's soooo smart!"_ - @PeHaa
Video[](#video "Direct link to Video")
----------------------------------------
Detailed walkthrough
Of course like all GreenSock tools, there's a rich API for finessing effects and getting exactly the look you want.
"**FLIP**" is an animation technique that stands for "**F**irst", "**L**ast", "**I**nvert", "**P**lay" and was coined [by Paul Lewis](https://aerotwist.com/blog/flip-your-animations/)
. Here's a demo of how it works:
#### loading...
Features[](#features "Direct link to Features")
-------------------------------------------------
Feature Highlights
* **Nested transforms? No problem!** Most FLIP libraries only calculate basic offsets assuming no transforms beyond x/y, so a scaled parent breaks things. Rotations certainly aren't allowed. GSAP's Flip plugin **just works**!
* Set `absolute: true` to **make elements use `position: absolute` during the flip**. This solves layout challenges with flexbox, grid, etc. You can even define a subset of targets, like `absolute: ".box"`
* One flip can handle **multiple elements** and even stagger them.
* **Resize via width/height properties** (default) **or scaleX/scaleY** (`scale: true`)
* You get the **full power of GSAP under the hood**, so you can use any `ease`, define special properties like `onComplete`, `onUpdate`, `repeat`, `yoyo`, and even `add()` other animations with total control of timing, etc.
**read more...**
* **Apply a CSS class during the flip with `toggleClass`**. It'll be removed at the end of the flip.
* **[Flip.fit()](/docs/v3/Plugins/Flip/static.fit())
repositions/resizes one element to fit perfectly on top another (or even a previous state of the same element)**.
* **Compensate for nested offsets**. If a container element is getting flipped along with some of its children, set `nested: true` to prevent the offsets from compounding.
* **Smoothly handles interruptions**.
* **Flip one element to another**; even have them cross-fade (`fade: true`). Just give them the same `data-flip-id` attribute to correlate them.
* **`onEnter` and `onLeave` callbacks** for when elements enter or leave (like if the flip senses a `display: none` toggle and there's no matching target to swap), making it easy to elegantly animate on/off elements.
* **Batch** multiple Flip animations so they don't step on each other's toes, like in a React app with multiple independent components that need to work together.
How does Flip work?[](#how-does-flip-work "Direct link to How does Flip work?")
---------------------------------------------------------------------------------
There are typically 3 steps to a "FLIP" animation:
1. ### Get the current state[](#get-the-current-state "Direct link to Get the current state")
// returns a state object containing data about the elements' current position/size/rotation in the viewportconst state = Flip.getState(".targets");
This merely captures some data about the current state. Use selector text, an Element, an Array of Elements, or NodeList. [Flip.getState()](/docs/v3/Plugins/Flip/static.getState())
doesn't alter anything (unless there's an active flip animation affecting any of the targets in which case it will force it to completion to capture the final state accurately). By default, Flip only concerns itself with position, size, rotation, and skew. If you want your Flip animations to affect other CSS properties, you can define a configuration object with a comma-delimited list of `props`, like:
// record some extra properties (optional)const state = Flip.getState(".targets", { props: "backgroundColor,color" });
2. ### Make your state changes[](#make-your-state-changes "Direct link to Make your state changes")
Perform DOM edits, styling updates, add/remove classes, or whatever is necessary to get things in their final state. There's no need to do that through the plugin (unless you're [batching](/docs/v3/Plugins/Flip/static.batch())
). For example, we'll toggle a class:
// make state changes. We'll toggle a class, for example:element.classList.toggle("full-screen");
3. ### Call `Flip.from(state, options)`[](#call-flipfromstate-options "Direct link to call-flipfromstate-options")
Flip will look at the `state` object, compare the recorded positions/sizes to the current ones, immediately reposition/resize them to _appear_ where they were in that previous state, and then animate the _removal_ of those offsets. You can specify almost any standard tween special properties like `duration`, `ease`, `onComplete`, etc. [Flip.from()](/docs/v3/Plugins/Flip/static.from())
returns a timeline that you can `add()` things to or control in any way:
// animate from the previous state to the current one:Flip.from(state, { duration: 1, ease: "power1.inOut", absolute: true, onComplete: myFunc,});
**_That's it!_**
Simple example[](#simple-example "Direct link to Simple example")
-------------------------------------------------------------------
#### loading...
Flex example[](#flex-example "Direct link to Flex example")
-------------------------------------------------------------
#### loading...
Advanced example[](#advanced-example "Direct link to Advanced example")
-------------------------------------------------------------------------
#### loading...
**Config Object**[](#config-object "Direct link to config-object")
--------------------------------------------------------------------
The [Flip.from()](/docs/v3/Plugins/Flip/static.from())
options object (2nd parameter) can contain any of the following optional properties **in addition to any standard tween properties like `duration`, `ease`, `onComplete`**, etc. as described [here](/docs/v3/GSAP/gsap.to())
:
### Property
### Description
* #### absolute[](#absolute)
Boolean | String | Array | NodeList | Element - specifies which of the targets should have `position: absolute` applied during the course of the FLIP animation. If `true`, **all** of the targets are affected, or use selector text like `".box"` (or an Array/NodeList of Elements, or even a single Element) to specify a subset of the targets. This can solve layout challenges with flex and grid layouts, for example. If things aren't behaving in a seamless way, try setting `absolute: true`. Beware, that `position: absolute` removes the elements from document flow, so things below can collapse. In that case, just define a subset that doesn't include the container element so it props the layout open. _(added in 3.9.0)_
* #### absoluteOnLeave[](#absoluteOnLeave)
Boolean - if `true`, any "leaving" Elements (ones passed to the `onLeave()`) will be set to `position: absolute` during the flip animation. This can be very useful when you set elements to `display: none` to hide them in the final state, but you want to animate them out (fade, scale, whatever). It's critical that they not affect layout but you still want them visible during the animation. _(added in 3.9.0)_
* #### fade[](#fade)
Boolean - by default, if the target element associated with a particular `data-flip-id` in the previous state is a **different element** than the one with the same `data-flip-id` in the end state, it will get swapped immediately but if you'd prefer that they cross-fade, set `fade: true`. Again, this only applies when swapping elements. If the "swapping out" (leaving) element is `display: none` (CSS), obviously it won't be visible for fading but if you set the Flip to `absolute: true`, it will force the element to the previous display state _during_ the flip so that it can cross-fade. The reason `absolute: true` is necessary in this case is because otherwise the element would affect document flow and throw off the positioning of other elements but if it is `position: absolute` (CSS), it's removed from the document flow and won't contaminate positioning.
* #### nested[](#nested)
Boolean - if the Flip has any _nested_ targets (like a parent and its child are both in the `targets`), set `nested: true` to have Flip perform extra calculations to prevent those movements from compounding. A parent's movement affects its children, so if both are mapped to end up 200px from their original position and Flip moves them both 200px, the child would end up moving 400px unless `nested: true` is set.
* #### onEnter[](#onEnter)
Function - A callback that's called if/when a target either isn't found in the original `state` or it was not in the document flow in that original state (like `display: none`), but it _IS_ in the document flow in the **end** state. Since there is no position/size data to compare to in the original state, it won't be included in the flip animation, but the callback receives an Array of the entering elements as a parameter so that you can animate them as you please (like fade them in). Any animation returned by this callback will get added to the flip timeline so that it gets forced to completion if a competing flip interrupts it. For example:
onEnter: elements => gsap.fromTo(elements, {opacity: 0}, {opacity: 1})
* #### onLeave[](#onLeave)
Function - A callback that's called if/when a target is in the original `state` but not the end state, or if it isn't in the document flow in the end state (like `display: none`). Since there is no position/size data to compare to in the end state, it won't be included in the flip animation, but the callback receives an Array of the leaving elements as a parameter so that you can animate them as you please (like fade them out). **IMPORTANT:** these elements won't be visible unless you also set `absolute: true` (otherwise, it'd throw off document flow). If `absolute: true` is set, it will force `display` to whatever it was in the previous state and then revert it back at the end of the flip. Any animation returned by this callback will get added to the flip timeline so that it gets forced to completion if a competing flip interrupts it. For example:
onLeave: elements => gsap.fromTo(elements, {opacity: 1}, {opacity: 0})
* #### props[](#props)
String - a comma-delimited list of _camelCased_ CSS properties that should be included in the flip animation beyond the standard positioning/size/rotation/skew ones. For example, `"backgroundColor,color"`. This will only work, however, if the props exist in the `state` object (first parameter) because otherwise there's no corresponding data to pull from. By default, Flip will use the `props` that were captured in the state with [Flip.getState(targets, props)](/docs/v3/Plugins/Flip/static.getState())
, so it's very rare that you'd need to define `props` in [Flip.from()](/docs/v3/Plugins/Flip/static.from())
. It's only useful if you want to _LIMIT_ them to a subset of the ones captured in the state.
* #### prune[](#prune)
Boolean - if `true`, Flip will remove any targets from the animation that match the previous state (position/size) in order to conserve resources. This requires a little more processing up-front, but it may improve performance during the animation when several get removed, plus it also makes staggering more intuitive since you may not want non-animating targets to be factored into the staggering. _(added in 3.9.0)_
* #### scale[](#scale)
Boolean - by default, Flip will affect the `width` and `height` CSS properties to alter the size, but if you'd rather scale the element instead (typically better performance), set `scale: true`.
* #### simple[](#simple)
Boolean - if `true`, Flip will skip the extra calculations that would be necessary to accommodate rotation/scale/skew in determining positions. It's like telling Flip _"I promise that there aren't any rotated/scaled/skewed containers for the Flipping elements"_ which makes things **faster**. In most cases, the performance difference isn't noticeable, but if you're flipping a lot of elements it can help keep things snappy.
* #### spin[](#spin)
Boolean | Number | Function -
if `true`, the elements will spin an extra 360 degrees during the flip animation which makes it look a little more fun. Or you can define a **number** of full rotations, including a negative number, so `-1` would spin in the opposite direction once. If you provide a **function**, it will be called once for each target so that you can return whatever value you'd like for each individual element's spin. This allows you to, for example, have certain targets spin one direction, other elements spin another direction, or return 0 to not spin at all. Sample code: ...
Flip.from(state, { spin: (index, target) => { if (target.classList.contains("clockwise")) { return 1; } else if (target.classList.contains("counter-clockwise")) { return -1; } else { return 0; } },})
* #### targets[](#targets)
String | Element | Array | NodeList - by default, Flip will use the targets from the `state` object (first parameter), but you can specify a subset of those as either selector text (`".class, #id"`), an Element, an Array of Elements, or a NodeList. If any of the targets provided is NOT found in the `state` object, it will be passed to the `onEnter` and _not_ included in the flip animation because there's no previous state from which to pull position/size data.
* #### toggleClass[](#toggleClass)
String - adds a CSS class to the targets while the flip animation is in progress. For example `"flipping"`.
* #### zIndex[](#zIndex)
Number - immediately sets the zIndex CSS property to this value for the entire course of the flip animation and then reverts at the end. This makes it easy to ensure that your flipping elements are on top of other elements during the animation, for example.
How do I flip between two _different_ elements?[](#how-do-i-flip-between-two-different-elements "Direct link to how-do-i-flip-between-two-different-elements")
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Flip looks for a `data-flip-id` attribute on every element it interacts with (via [Flip.getState()](/docs/v3/Plugins/Flip/static.getState())
or [Flip.from()](/docs/v3/Plugins/Flip/static.from())
, etc.) and if one isn't found, Flip assigns an incremented one automatically ("auto-1", "auto-2", etc.). It lets you correlate targets (the target with the `data-flip-id` of `"5"` in the "from" state gets matched up with the target with a `data-flip-id` of `"5"` in the end state). The `data-flip-id` can be any string, not just a number.
So if you want to flip between two different targets, make sure the data-flip-id attribute in the end state matches the one in the "from" state. When Flip sees that there are two with the same value in the from/end state, it will automatically figure out which one is disappearing (typically with `display: none`) and base things off of that to "swap" the elements. If you want them to crossfade, simply set `fade: true`, otherwise they'll immediately swap. And it is typically best to set `absolute: true` so that when Flip alters the `display` value, it doesn't affect the document flow.
#### loading...
Batching[](#batching "Direct link to Batching")
-------------------------------------------------
What if you need to create **multiple** coordinated Flip animations (perhaps in various React components)? They'd need to all [.getState()](/docs/v3/Plugins/Flip/static.getState())
_BEFORE_ any of them make their changes to the DOM/styling because doing so could alter the position/size of the other elements. See the docs for [Flip.batch()](/docs/v3/Plugins/Flip/static.batch())
for details.
Caveats & Tips[](#caveats--tips "Direct link to Caveats & Tips")
------------------------------------------------------------------
* Flip does not accommodate 3D transforms (like rotationX, rotationY, or z).
* It is strongly recommended that you use `box-sizing: border-box` on your elements to ensure accurate width/height calculations.
* When `absolute: true` is set, remember that coordinates will be calculated based on the current viewport, so if the viewport size changes or the user scrolls DURING the flip, it may affect positioning (but once the flip is done and the offsets are removed, things will be where they should be). In other words, in-progress flipping isn't always responsive.
* Set any transform-related values (x, y, scale, rotation, etc.) [directly via GSAP](/resources/mistakes#transforms)
whenever possible (instead of just in CSS classes or inline) because GSAP caches transform-related data to supercharge performance and maximize accuracy. To clear GSAP's cache on a particular element (which you'd never need to do if you're making all your changes via GSAP), `gsap.set(element, {clearProps: "transform"});`
Deep Dive - Using a framework like Vue, React or Angular?
Beware that frameworks often **DON'T** render changes immediately, so you should wait until the render occurs _before_ initiating the [Flip.from()](/docs/v3/Plugins/Flip/static.from())
. [Batching](/docs/v3/Plugins/Flip/static.batch())
may be an excellent option because you can `batch.getState(true)` and then perhaps a `useLayoutEffect(() => batch.run(true), [...])` in React. Another hack would be to use requestAnimationFrame() to wait one tick: `requestAnimationFrame(() => Flip.from(...));`
When you `Flip.getState(".your-class")`, it records position/size data for the elements with ".your-class" at that time, remembering **those particular elements** and their `data-flip-id` attribute values. Then, if you `Flip.from(yourState)`, and don't specify any `targets`, it will default to using the elements that were captured in the getState() but your framework may have re-rendered entirely new element instances (even if they look the same), thus they won't animate because Flip doesn't know to look at those new elements. The original ones were completely removed from the DOM, hence the need to tell the Flip _"use these new targets and search the state object for the IDs that match..."_. So make sure you define `targets` like this:
// BADFlip.from(state, { duration: 1,});// GOODFlip.from(state, { targets: ".your-class", // <-- BINGO! duration: 1,});
And don't forget that you'll probably need to set a `data-flip-id` on those elements to make sure Flip knows which target matches up with which one from the captured state.
Showcase & how-to demos[](#showcase--how-to-demos "Direct link to Showcase & how-to demos")
---------------------------------------------------------------------------------------------
* [Flip showcase](https://codepen.io/collection/d725bcacb2f44bbdf0f44718f7ebbf55)
* [Flip how-to demos](https://codepen.io/collection/4a605f253549434210c139fa331704cb)
**Methods**[](#methods "Direct link to methods")
--------------------------------------------------
| | |
| --- | --- |
| #### [Flip.batch](/docs/v3/Plugins/Flip/static.batch())
( id:String ) : FlipBatch | Coordinates the creation of multiple Flip animations in the properly sequenced set of steps to avoid cross-contamination. |
| #### [Flip.fit](/docs/v3/Plugins/Flip/static.fit())
( targetToResize:String \| Element, destinationTargetOrState:String \| Element \| FlipState, vars:Object ) ; | Repositions/resizes one element so that it appears to fit exactly into the same area as another element. Using the `fitChild` special property, you can even scale/reposition an element so that one if its _child_ elements is used for the fitting calculations instead! By default it alters the transforms (x, y, rotation, and skewX) as well as the width and height of the element, but if you set `scale: true` it will use scaleX and scaleY instead of width and height. |
| #### [Flip.from](/docs/v3/Plugins/Flip/static.from())
( state:FlipState, vars:Object ) : Timeline | Immediately moves/resizes the targets to match the provided `state` object, and then animates backwards to remove those offsets to end up at the current state. By default, `width` and `height` properties are used for the resizing, but you can set `scale: true` to scale instead (transform). It returns a timeline animation, so you can control it or add() other animations. |
| #### [Flip.getState](/docs/v3/Plugins/Flip/static.getState())
( targets:String \| Element \| Array, vars:Object ) : Object | Captures information about the current state of the `targets` so that they can be Flipped later. By default, this information includes the dimensions, rotation, skew, opacity, and the position of the targets in the viewport. Other properties can be captured by configuring the `vars` parameter. |
| #### [Flip.isFlipping](/docs/v3/Plugins/Flip/static.isFlipping())
( target:String \| Element ) : Boolean | Returns `true` if the given target is currently being Flipped. Otherwise returns `false`. |
| #### [Flip.killFlipsOf](/docs/v3/Plugins/Flip/static.killFlipsOf())
( targets:String \| Array \| NodeList \| Element, complete:boolean ) ; | Immediately kills the Flip animation associated with any of the targets provided. |
| #### [Flip.makeAbsolute](/docs/v3/Plugins/Flip/static.makeAbsolute())
( targets:String \| Element \| Array \| NodeList \| FlipState ) : Array | Sets all of the provided target elements to `position: absolute` while retaining their current positioning. |
| #### [Flip.to](/docs/v3/Plugins/Flip/static.to())
( state:FlipState, vars:Object ) : Timeline | Identical to [Flip.from()](/docs/v3/Plugins/Flip/static.from())
except inverted, so this would animate **to** the provided state (from the current one). |
FAQ[](#faq "Direct link to FAQ")
----------------------------------
#### How do I include Flip in my project?
See the [installation page](/docs/v3/Installation)
for all the options (CDN, NPM, download, etc.) where there's even an interactive helper that provides the necessary code. Easy peasy. Don't forget to [register Flip](/docs/v3/GSAP/gsap.registerPlugin())
like this in your project:
gsap.registerPlugin(Flip)
#### Is this included in the GSAP core?
No, you must load/import it separately
#### Is this only for Club GSAP members?
No, it's available to everyone for free! But [Club GSAP](https://gsap.com/pricing/)
is pretty awesome...just sayin'.
#### It works fine during development, but suddenly stops working in the production build! What do I do?
Your build tool is probably dropping the plugin when [tree shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking)
and you forgot to [register Flip](/docs/v3/GSAP/gsap.registerPlugin())
(which protects it from tree shaking). Just register the plugin like this:
gsap.registerPlugin(Flip)
#### Is it bad to register a plugin multiple times?
No, it's perfectly fine. It doesn't help anything, nor does it hurt.
Contents
--------
* [Video](#video)
* [Features](#features)
* [How does Flip work?](#how-does-flip-work)
* [Simple example](#simple-example)
* [Flex example](#flex-example)
* [Advanced example](#advanced-example)
* [**Config Object**](#config-object)
* [How do I flip between two _different_ elements?](#how-do-i-flip-between-two-different-elements)
* [Batching](#batching)
* [Caveats & Tips](#caveats--tips)
* [Showcase & how-to demos](#showcase--how-to-demos)
* [**Methods**](#methods)
* [FAQ](#faq)
---
# GSAP | GSAP | Docs & Learning
[Skip to main content](#__docusaurus_skipToContent_fallback)
On this page
GSAP
====
The `gsap` object serves as the access point for most of GSAP's functionality. It's just a generic object with various methods and properties that create and control [Tweens](/docs/v3/GSAP/Tween)
and [Timelines](/docs/v3/GSAP/Timeline)
, two of the most important concepts to understand.
Quick Overview
For a quick overview of the GSAP object, check out this video from the ["GSAP 3 Express" course](https://courses.snorkl.tv/courses/gsap-3-express?ref=44f484)
by Snorkl.tv - one of the best ways to learn the basics.
To get the most out of GSAP, it's crucial that you understand what Tweens and Timelines are:
### What's a Tween?[](#whats-a-tween "Direct link to What's a Tween?")
A [Tween](/docs/v3/GSAP/Tween)
is what does all the animation work - think of it like a **high-performance property setter**. You feed in targets (the objects you want to animate), a duration, and any properties you want it to animate and then when the Tween's playhead moves to a new position, figures out what the property values should be at that point applies them accordingly.
#### Common methods for creating a Tween:[](#common-methods-for-creating-a-tween "Direct link to Common methods for creating a Tween:")
* [gsap.to()](/docs/v3/GSAP/gsap.to())
* [gsap.from()](/docs/v3/GSAP/gsap.from())
* [gsap.fromTo()](/docs/v3/GSAP/gsap.fromTo())
For simple animations (no fancy sequencing), the methods above are all you need! For example:
//rotate and move elements with a class of "box" ("x" is a shortcut for a translateX() transform) over the course of 1 second.gsap.to(".box", { rotation: 27, x: 100, duration: 1 });
#### loading...
You can do basic sequencing by using the `delay` special property, but Timelines make sequencing and complex choreography much, much easier.
### What's a Timeline?[](#whats-a-timeline "Direct link to What's a Timeline?")
A [Timeline](/docs/v3/GSAP/Timeline)
is a **container for Tweens.** It's the ultimate sequencing tool that lets you position animations in time wherever you want and then control the whole sequence easily with methods like [pause()](/docs/v3/GSAP/Timeline/pause())
, [play()](/docs/v3/GSAP/Timeline/play())
, [progress()](/docs/v3/GSAP/Timeline/progress())
, [reverse()](/docs/v3/GSAP/Timeline/reverse())
, [timeScale()](/docs/v3/GSAP/Timeline/timeScale())
, etc.
Create as many Timelines as you want. You can even **nest them** which is fantastic for modularizing your animation code! Every animation (Tween and Timeline) gets placed onto a parent timeline (the [globalTimeline](/docs/v3/GSAP/gsap.globalTimeline())
by default). Moving a Timeline's playhead cascades down through its children so that the playheads stay aligned. A Timeline is purely about grouping things and coordinating time/playheads - it never actually sets properties on targets (Tweens handle that).
PLAYHEAD|--------------timeline-----|-----------||--tween1--| | |-----tween2-----|-----------|
#### Method for creating a Timeline:[](#method-for-creating-a-timeline "Direct link to Method for creating a Timeline:")
* [gsap.timeline()](/docs/v3/GSAP/gsap.timeline())
GSAP's API lets you control virtually anything on-the-fly, such as the playhead position, the [startTime](/docs/v3/GSAP/Tween/startTime())
of any child, even play/pause/reverse the timeline or alter the timeScale itself.
Sequencing things in a Timeline[](#sequencing-things-in-a-timeline "Direct link to Sequencing things in a Timeline")
----------------------------------------------------------------------------------------------------------------------
First, create a Timeline:
var tl = gsap.timeline();
Then add a tween using one of the convenience methods - [to()](/docs/v3/GSAP/Timeline/to())
, [from()](/docs/v3/GSAP/Timeline/from())
, or [fromTo()](/docs/v3/GSAP/Timeline/fromTo())
:
tl.to(".box", { duration: 2, x: 100, opacity: 0.5 });
Do that as many times as you want. Notice we're calling `.to()` **on the timeline instance** (the variable `tl` in this case), not the `gsap` object. This creates a tween and immediately puts it into that particular Timeline. `gsap.to()`, on the other hand, creates a standalone tween. By default, the animations will be sequenced one-after-the-other. You can even use method chaining to simplify your code like this:
//sequenced one-after-the-othertl.to(".box1", { duration: 2, x: 100 }) //notice that there's no semicolon! .to(".box2", { duration: 1, y: 200 }) .to(".box3", { duration: 3, rotation: 360 });
**Note:** The whole GSAP platform is object-oriented and you could create individual tween instances with [gsap.to()](/docs/v3/GSAP/gsap.to())
, for example, and then [timeline.add()](/docs/v3/GSAP/Timeline/add())
each one but it's just easier to call .to(), .from(), or .fromTo() directly on the Timeline instance to do the same thing in fewer steps.
#### loading...
Control placement with the position parameter[](#control-placement-with-the-position-parameter "Direct link to Control placement with the position parameter")
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Define **exactly** where you want your animations to be placed into the timeline by using the optional position parameter. A number indicates an absolute time (in seconds), or a string with a `"+="` or `"-="` prefix indicates an offset relative to the END of the timeline. For example, `"+=2"` would be 2 seconds after the end, creating a 2-second gap. `"-=2"` would create a 2-second overlap.
//starts at EXACTLY 1.5 seconds from the start of the Timeline:tl.to(..., 1.5) .to(..., "-=0.75") //overlaps by 0.75 seconds .to(..., "+=1") //adds a 1-second gap before
Labels[](#labels "Direct link to Labels")
-------------------------------------------
Use labels to mark certain spots on the timeline so that you can place animations there or navigate there during playback.
//add a label at exactly 3 secondstl.addLabel("step2", 3) .to(..., "step2") //starts at the step2 label .to(..., "step2+=0.75") //0.75 seconds after the step2 label//then later, we can seek() to that spot:tl.seek("step2");
Controlling Tweens and Timelines[](#controlling-tweens-and-timelines "Direct link to Controlling Tweens and Timelines")
-------------------------------------------------------------------------------------------------------------------------
[Tween](/docs/v3/GSAP/Tween)
and [Timeline](/docs/v3/GSAP/Timeline)
both extend an Animation class that exposes a myriad of useful methods and properties. Here are some of the most frequently used:
* [pause()](/docs/v3/GSAP/Tween/pause())
* [play()](/docs/v3/GSAP/Tween/play())
)
* [progress()](/docs/v3/GSAP/Tween/progress())
* [restart()](/docs/v3/GSAP/Tween/restart())
* [resume()](/docs/v3/GSAP/Tween/resume())
* [reverse()](/docs/v3/GSAP/Tween/reverse())
* [seek()](/docs/v3/GSAP/Tween/seek())
* [time()](/docs/v3/GSAP/Tween/time())
* [duration()](/docs/v3/GSAP/Tween/duration())
* [timeScale()](/docs/v3/GSAP/Tween/timeScale())
* [kill()](/docs/v3/GSAP/Tween/kill())
You can reference the Tween or Timeline instance with a variable, and then control it whenever you want:
//you only need to create a variable if you want to control it later...var tween = gsap.to(...);var tl = gsap.timeline(); //"tl" short for timelinetl.to(...).to(...); //add animations.//now we can control them...tween.pause();tween.timeScale(2); //double speedtl.seek(3); //jump to 3 seconds intl.progress(0.5); //halfway through...
Contents
--------
* [What's a Tween?](#whats-a-tween)
* [What's a Timeline?](#whats-a-timeline)
* [Sequencing things in a Timeline](#sequencing-things-in-a-timeline)
* [Control placement with the position parameter](#control-placement-with-the-position-parameter)
* [Labels](#labels)
* [Controlling Tweens and Timelines](#controlling-tweens-and-timelines)
---
# HelperFunctions | GSAP | Docs & Learning
[Skip to main content](#__docusaurus_skipToContent_fallback)
Over the years Jack has "whipped together" various GSAP-related helper functions for [community](https://gsap.com/community/)
members, so we gathered them into one place for convenience. We'll keep adding relevant helper functions here as we craft them. Enjoy!
Browse the [helper function collection](https://codepen.io/collection/eJwrak)
Available Helpers[](#available-helpers "Direct link to Available Helpers")
----------------------------------------------------------------------------
| | |
| --- | --- |
| #### [Seamlessly loop elements along the x or y axis](/docs/v3/HelperFunctions/helpers/seamlessLoop) | Like a slider or news ticker, where elements go off one side and then eventually come back around from the other side. This helper function does all the hard work for you |
| #### [Stop overscroll behavior, even on iOS Safari](/docs/v3/HelperFunctions/helpers/stopOverscroll) | It should be as simple as setting overscroll-behavior: none in your CSS, but iOS Safari won't cooperate! So here's a function that'll help stop the overscroll behavior: |
| #### [Hook a Lottie animation up to ScrollTrigger](/docs/v3/HelperFunctions/helpers/LottieScrollTrigger) | Tie a Lottie animation to the scroll position with this handy function so that as the user scrolls, the animation progresses |
| #### [addWeightedEases](/docs/v3/HelperFunctions/helpers/addWeightedEases) | Feed in a ratio between -1 and 1 to any of the standard (non-configurable) eases to make them "weighted" in one direction or the other |
| #### [Change transformOrigin without a jump](/docs/v3/HelperFunctions/helpers/alignOrigins) | change transformOrigin dynamically without a jump |
| #### [anchorsToProgress](/docs/v3/HelperFunctions/helpers/anchorsToProgress) | Calculate all the progress values for the anchor points on a path so that, for example, you could use DrawSVG to animate point-by-point (requires [MotionPathPlugin](/docs/v3/Plugins/MotionPathPlugin)
) |
| #### [Animating backgroundSize:"cover" or "contain"](/docs/v3/HelperFunctions/helpers/bgSize) | Animate between \`backgroundSize\` of \`"cover"\` or \`"contain" |
| #### [blendEases](/docs/v3/HelperFunctions/helpers/blendEases) | If you need one ease at the start of your animation, and a different one at the end, you can use this function to blend them! |
| #### [Call a function after viewport resizing stops (debounced)](/docs/v3/HelperFunctions/helpers/callAfterResize) | "resize" events get dispatched many times while the user is dragging the browser window's edges, so if you run an expensive function on every resize event, it can really bog things down. Here's a function that will wait to call your function until a certain amount of time has elapsed since the user STOPPED resizing the window |
| #### [Compensated skews](/docs/v3/HelperFunctions/helpers/compensatedSkew) | This is a special method that you can apply via an onUpdate to make a tween render skews in the old skewType: "compensated" way from GSAP 2. Note that it affects an element's scaleX/scaleY (hence "compensated")! This assumes skews are degree-based, and only works in GSAP 3. |
| #### [Directional snapping](/docs/v3/HelperFunctions/helpers/getDirectionalSnapFunc) | Snap to a value in a specified direction - greater or lesser |
| #### [Estimate where an ease will hit a certain value](/docs/v3/HelperFunctions/helpers/easeToLinear) | An ease accepts a normalized progress value (0-1) and returns the corresponding eased value, but what if you want to know when that eased value will hit a specific ratio like 0.7? For example, a \`"power2.out"\` ease may hit 0.7 when the linear progress is only around 0.33. This function lets you feed in that 0.7 and get the linear progress value (0.33 in this example) |
| #### [Simple FLIP](/docs/v3/HelperFunctions/helpers/FLIP) | If you're shifting things around in the DOM and then you want elements to animate to their new positions, the most full-featured way to handle it is with the [Flip Plugin](/docs/v3/Plugins/Flip)
, but if you're only doing basic things you can use this helper function (see the comments at the top to learn how to use it): |
| #### [Format number with commas and limited decimal places](/docs/v3/HelperFunctions/helpers/formatNumber) | Take a number like 1000.254145 and format it into a string like "1,000.25". |
| #### [Find a nested label's time](/docs/v3/HelperFunctions/helpers/getNestedLabelTime) | Labels are timeline-specific, so you can't tell a timeline to move its playhead to a label that exists in a nested timeline. So here's a helper function that lets you find a nested label and calculate where that lines up on the parent timeline |
| #### [Get the scroll position associated with an element (ScrollTrigger-aware)](/docs/v3/HelperFunctions/helpers/getScrollLookup) | This function even takes ScrollTrigger pinning into account in most situations. Feed it your target elements and it'll return a function that you can call later, passing it a specific one of those target elements and it'll return the scroll position. It even adjusts when the viewport resizes (responsive). |
| #### [Get the scroll position associated with a particular ScrollTriggered animation](/docs/v3/HelperFunctions/helpers/getScrollPosition) | Perhaps you want to scroll the page to the exact spot where a particular scroll-triggered animation starts (or ends or any progress value) - just feed this helper function your animation (it must have a ScrollTrigger of course) and optionally a progress value (0 is when the animation starts, 0.5 is halfway through, 1 is the end) and it'll return the scroll position which you could feed into a scrollTo tween |
| #### [Scrub through a canvas image sequence](/docs/v3/HelperFunctions/helpers/imageSequenceScrub) | Create an Array of image URLs, feed it to this helper function along with a reference to your `