mount → initial state → intro → settled → outro → end state → unmount
Mount and unmount belong to React; animation owns the five phases between them. React Router has no leave hook: hold navigation with a blocker or intercept it before it starts. Parameter changes can reuse the route element.
Keep the requested look and existing project conventions. Add GSAP/plugins only as needed; do not replace the chosen animation library unless asked.
This skill decides when motion runs. For what moves, and for a feel such as premium or playful, also load the animaxxing skill when it is installed: its recipes and its guide to finding the vibe plug into this lifecycle.
Start with the project
Read repository instructions, existing animation, layouts, navigation, CSS, accessibility conventions, and checks. Then:
- Confirm React Router 7 or later and its mode. Framework mode has
react-router.config.ts,routes.ts,root.tsx, andHydratedRouterinentry.client.tsx. Data mode hascreateBrowserRouterandRouterProvider. Declarative mode hasBrowserRouterand no loaders, nouseNavigation, and no blocker. A Remix 2 app uses the same hooks from@remix-run/react; say so and map the names. - Read the installed version from
node_modules/react-router/package.json. The package ships itsdocs/,CHANGELOG.md, and.d.tsfiles indist/; prefer them over memory. Version gates:useBlocker(6.19),viewTransitionanduseViewTransitionState(6.27),Link maskanduseTransitions(7.15), middleware (7.9 behindfuture.v8_middleware, always on in 8). Version 8 is ESM-only, needs React 19.2, and dropsreact-router-dom:RouterProviderandHydratedRoutercome fromreact-router/dom. - In framework mode check
ssrandprerenderinreact-router.config.ts. Server-rendered and prerendered pages paint HTML before hydration.ssr: falseships anindex.htmlholding only the root route and itsHydrateFallback, so route content renders after hydration and needs no pre-paint rule. Data and declarative mode without server rendering are the same.
Choose the engine
In data/framework mode, use Link, Form, or navigate with viewTransition for snapshot morphs or page crossfades. Use GSAP for live-DOM outros that gate navigation, interruptible sequences, split text, or scroll-linked motion. One engine per element; see combining engines.
Read only what you need
- Invisible entrances, failed initialization, indexing, and first-load performance: Initialization and recovery, plus the framework integration.
- The blocker outro, transition-aware links, the lock, pending state, back and forward, the swap gap, scroll, focus, View Transitions: React Router navigation.
- Modes and their hooks, route reuse versus remount, layouts and
<Outlet>, SSR and SPA mode first paint, streaming, fetchers, modal routes: Route lifetime. - The five phases, GSAP setup, React lifecycle, show and hide, layout stability, scroll, text, plugins: Lifecycle implementation.
- Lenis, ScrollSmoother, or eased page scrolling across routes: Smooth scrolling, plus the React Router integration.
- Curtains, first-visit preloaders, and shared-element morphs: Transition archetypes, plus where they live under React Router.
- Touch, viewport changes, and device budgets: Devices and input.
- Before calling work done: Verification.
Install the official GSAP skills alongside this repository. Load gsap-core for API details and gsap-react for component setup only as needed.
Rules
- Preserve invisible intros on successful setup; recover the current incoming owner on failure. Follow the initialization contract before adding hiding rules.
- GSAP runs only in the browser. Framework mode evaluates route modules on the server, so keep GSAP calls inside
useGSAPor effects and registration in a.clientside-effect module. ImportgsapanduseGSAPfrom their packages:.clientexports are undefined during SSR. Scope selectors. Clean up every tween, trigger, split, and listener. - Reserve final geometry with normal CSS and a stable wrapper; overlap outgoing/incoming content without doubling layout space.
- Mount, then set initial values, then paint. Server HTML paints before hydration: hide intro targets only under a root attribute set by an inline script in the root
Layout, only during the initial phase, with a no-JavaScript path. - Clear temporary styles at settled. Use
will-changeonly while animating; this overridesgsap-performance's static hint. - Use capability queries for device tiers. Touch states release; controls work without hover.
- Keep outgoing routes mounted and visible through outro and end state. The router unmounts the old route when the new one commits, so hold the commit:
useBlockerandproceed()from the end callback, or prevent the Link default andnavigateafter the outro. - Never block or outro a
POP. Back and forward get initial state and intro only, after scroll restoration. - A navigation to the same route with new params reuses the element. Key the outlet on
location.pathname, or run the lifecycle again from apathnamedependency against DOM that already holds settled values. - Loaders run after
proceed(), so the end state waits for data. Prefetch on intent and cover the route container until the incoming targets are prepared. - A fetcher is not a navigation. Do not treat
fetcher.stateas a page transition. - One engine per element. A named view transition and a GSAP tween on the same node fight.
- Keep native link behavior: modified clicks,
target,reloadDocument, external URLs,prefetch,NavLinkstate, focus, scroll, and no-JavaScript readability. - Reduced motion reaches the same settled state and still fires every completion callback, including the one that calls
proceed(). - Define interruption and rapid-click behavior; completion must release navigation waits exactly once.
- Verify in a real browser when practical. Use a production build for route, config, dependency, or release changes.