← Back to Website builders
See how it helps
Framework animation integration
Coordinates animations with component lifecycles so rendering, cancellation and navigation do not compete for the same properties.
framework-animation-integration
Team members using this skill
When is it useful?
Use when exit animations flicker or continue after a component disappears.
What does it help you do?
- Assigns one owner to each animated DOM property.
- Coordinates exit completion with removal and a bounded fallback.
- Uses stable list keys and server-rendering-safe initialization.
Try asking this
Fix a closing panel that disappears before its animation finishes and leaves a running timer after navigation. Close, reopen and navigate away during the exit animation. The panel must finish in the requested state with no orphaned timer or hidden focus target.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Framework Animation Integration
Declarative UI frameworks (React, Vue, Angular) own the virtual/template DOM and unmount elements immediately when state flips to false. Imperative animation engines (WAAPI, GSAP, Canvas/Three.js) mutate real DOM nodes over time. Prevent the framework and the animation engine from fighting over the same properties.
Single Owner Rule for DOM Properties
- Never bind a reactive framework style prop and an imperative animation to the same CSS property on the same element: If a component re-renders mid-animation with
:style="{ transform: ... }"orstyle={{ opacity }}, the framework overwrites the animation engine's interpolated frame value. - Either let the framework's native transition primitive drive the state, or give the imperative animation a dedicated wrapper
<div ref="animEl">whosetransform/opacityis untouched by reactive template bindings.
Framework-Specific Lifecycle & Exit Patterns
| Framework | Idiomatic Entry / Exit & Layout Primitives | Imperative Timeline / Canvas Integration |
|---|---|---|
| React | Motion (<AnimatePresence> + <motion.div layout exit={{ ... }}> + useReducedMotion()) or CSS @starting-style |
Scope with useGSAP(() => { ... }, { scope: containerRef, dependencies: [...] }) or useLayoutEffect returning () => ctx.revert(). Never query document.querySelector outside containerRef. |
| Vue 3 | Built-in <Transition name="..." mode="out-in"> and <TransitionGroup> (includes built-in FLIP via .v-move transition class!), plus JavaScript hooks (@enter, @leave(el, done)) |
Create gsap.context(..., containerRef.value) or WAAPI handles in onMounted(), call done() in @leave hooks only after exit animation finishes, and always call ctx?.revert() in onUnmounted(). |
| Angular | @angular/animations (animate.enter / animate.leave, route transition triggers) or CSS transitions bound to host state signals |
Run continuous requestAnimationFrame, WAAPI, or GSAP loops via NgZone.runOutsideAngular(() => ...) so 60fps ticks never trigger change detection across the component tree; clean up via DestroyRef.onDestroy(...). |
Handling Unmount & Route Transitions Safely
- Wait for exit completion before DOM removal—with a fallback timeout:
- When using JS-driven exit hooks (Vue
@leave(el, done)or custom exit promises), always ensuredone()is called even if the animation is cancelled orprefers-reduced-motionskips it; otherwise the detached DOM node remains stuck in the document forever.
- When using JS-driven exit hooks (Vue
- Stable keys in animated lists:
<TransitionGroup>(Vue),<AnimatePresence>(React), and@for (...; track item.id)(Angular) rely on stable, unique item keys to calculate FLIP deltas and exit targets. Never use array index (index) as the key of an animated list.
- SSR & Hydration safety:
- Guard browser-only globals (
window,document,matchMedia,ResizeObserver,IntersectionObserver) behind mount hooks (onMounted,useEffect,afterNextRender) so server-side rendering and hydration complete without mismatches.
- Guard browser-only globals (
Included files 1
SKILL.md
