React

gsap.context()

gsap.context() is a GSAP method that collects every animation, timeline, and ScrollTrigger created inside a function so one `revert()` call cleans them all up at once. Its companion contextSafe wraps callbacks that run later (event handlers, delayed setup) so the animations they create also get tracked and reverted. Together they are how you stop GSAP from leaking tweens and firing on detached nodes when a React component unmounts or re-renders.

Updated June 30, 2026

Mechanics

How gsap.context and contextSafe work

React is the most-used framework at 69.9% developer usage (State of JS 2025), and its mount/unmount cycle is exactly what breaks naive GSAP code: tweens outlive the nodes they target. gsap.context() is GSAP's answer to that, documented as the cleanup primitive for React in the official guide (gsap.com/resources/React).

gsap.context(func, scope) runs func immediately and records every GSAP object created inside it. The optional second argument scopes selector strings, so gsap.to(".box", ...) inside the context only matches .box elements within that ref or element, not the whole page. The call returns a context object with a revert() method.

When you call ctx.revert(), it kills every tween, timeline, and ScrollTrigger the context recorded, and rolls inline styles back to where they started. In React you call it in the effect cleanup, so unmounting a component leaves no live tweens animating nodes that no longer exist.

raw gsap.context in useEffect

Why contextSafe exists

A context only records what runs while its function executes. Anything created afterward, like a tween inside a mousemove handler, is created outside that window, so the context never sees it and never reverts it. contextSafe solves that. It wraps a function so any GSAP created inside it is added back into the context, and the wrapped function no-ops once the context has been reverted, which is what stops a late pointer event from animating an unmounted node.

contextSafe via useGSAP

useGSAP wraps this for you

useGSAP() from @gsap/react runs your setup inside a gsap.context() and calls revert() on unmount automatically. You rarely call gsap.context() by hand in React anymore, but useGSAP returns contextSafe precisely because event-handler tweens still need it.
When

Reach for it when

  • Any GSAP code in a React or Next.js component, so unmount cleanup is automatic instead of hand-killed
  • Pointer or scroll handlers that create tweens after setup runs (magnetic hover, drag, cursor-follow) - wrap each in contextSafe
  • A component that mounts and unmounts repeatedly (modal, drawer, route change) where leaked ScrollTriggers would pile up
  • Scoping selector strings to one component so .title doesn't accidentally animate another section's .title
Alternatives

Use something else when

  • You're in plain Vue or Svelte, not React - use the framework's lifecycle hook plus gsap.context() directly, or onUnmounted/onDestroy to call revert()
  • You're in vanilla JS with no component lifecycle - a context still helps for teardown, but a single gsap.globalTimeline or manual .kill() is often enough
  • You only need to kill one specific tween - keep its reference and call tween.kill() rather than reverting a whole context
  • You want to keep the end state instead of rolling styles back - revert() undoes inline styles, so for a persistent final pose use tween.kill() or clearProps selectively
In production

Used in these Annnimate components

Every Annnimate React component runs its GSAP inside useGSAP with a scope ref, which is gsap.context() underneath. Two show both halves of the pattern:

  • The Magnetic Button wraps its mouseenter, mousemove, and mouseleave handlers in contextSafe so the cursor-follow tweens created on every pointer move are tracked by the context and stop cleanly when the button unmounts
  • The Text Reveal creates a SplitText instance and its line-mask tweens inside a scoped useGSAP, so the context reverts the split (puts the original markup back) and kills the ScrollTrigger on unmount instead of leaving orphaned line wrappers in the DOM

The leak you won't see in dev

A tween created in an event handler without contextSafe keeps running after unmount and throws 'cannot animate a null target' or silently mutates a detached node. It often passes a quick local test and only shows up after repeated mount/unmount cycles. If a component animates fine once but breaks after navigating away and back, an un-contextSafe handler is the usual cause.
Used in components

See it running in production

FAQ

Common questions

What's the difference between gsap.context and contextSafe?
gsap.context() records the GSAP objects created while its function runs and gives you a revert() to clean them up. contextSafe is for code that runs later, after that function finished, like an event handler. It re-adds those tweens into the context so they get reverted too, and makes the handler no-op once the context is gone. Setup uses context; anything triggered after setup uses contextSafe.
Do I still need gsap.context if I use useGSAP?
Not directly. useGSAP() runs your callback inside a gsap.context() and calls revert() for you on unmount, so you almost never write gsap.context() by hand in React. You still need contextSafe, though, which is why useGSAP hands it to you. Reach for raw gsap.context() only when you're not using the hook, for example inside a plain useEffect you control.
Why does my GSAP event handler animate after the component unmounts?
Because the tween was created inside a handler that ran after useGSAP/gsap.context() finished, so the context never recorded it and revert() never killed it. Wrap the handler in contextSafe and remove the listener in the cleanup return. Both steps matter: contextSafe tracks the tween, removing the listener stops the handler firing at all.
Does ctx.revert() remove the final state of my animation?
Yes. revert() rolls inline styles back to what they were before the context ran, which is exactly what you want on unmount but not if you wanted to keep the end pose. To hold a final state, kill the specific tween with tween.kill() instead of reverting the whole context, or write the end values to the element outside GSAP.
Can I scope selector strings to one component with gsap.context?
Yes, that's the second argument. Pass a ref or element as the scope and selector strings inside the context only match descendants of it. So gsap.to('.title', ...) animates the .title in this component, not every .title on the page. With useGSAP you pass the same thing as { scope: containerRef }.