Skip to main content

Page Transitions

Goal​

The default page transition system is designed to avoid visual flashes while still staying easy to replace.

It is intentionally separate from the loader so ReactWP can treat:

  • first load
  • critical route preparation
  • route swap
  • leave and enter animation

as related but distinct concerns.

Default Flow​

On client-side navigation, the current flow is:

  1. detect the next internal route and lock scrolling
  2. start the leave animation immediately while fetching the next route payload in parallel
  3. prepare the next template and critical assets as soon as the payload arrives, without waiting for leave to finish
  4. wait for both leave completion and critical preparation, then allow a paint before proceeding with the router
  5. render the new route and wait for its committed critical display and scroll placement
  6. run the enter animation to reveal the new content

A slow request extends the wait after leave; it does not postpone the start of leave. A cached or prefetched route still waits for leave to finish. Custom leave animations therefore run before the destination payload is available: use blocker.location for the requested location, and do not assume Loader.route() already contains the destination inside a leave factory.

If another navigation supersedes a pending request, its late response or failure cannot replace the active pending route or trigger an obsolete hard navigation. Returning to the current route during that wait restores the outgoing page through enter without fetching it again; ordinary same-route hashes still bypass leave and enter. Active fetch, critical preparation, paint, or Promise-based leave failures use the existing full-page navigation fallback, preserving the requested query and hash.

Back and forward navigation use the same flow because the transition hook sits on top of the router blocker.

The route component is keyed by normalized route.key, so route-specific React effects clean up and restart when pathname or search identity changes.

Main Files​

  • src/themes/reactwp/js/inc/PageTransition.js
  • src/themes/reactwp/js/inc/config/configurePageTransition.js

Responsibilities​

  • PageTransition.js contains the transition runtime and its default animations
  • config/configurePageTransition.js is the project-level customization point
  • Loader.js is separate and owns first-load behavior and asset preloading

This means the route transition layer focuses on leave and enter, while the loader handles the initial experience.

Default Target​

The shipped transition animates #viewport.

That is the shell-level container that wraps the smoother structure, which makes it a safe default for fading the whole current view in and out.

Initial Load Is Separate​

The page transition runtime does not own the first-load reveal.

The first load is handled by Loader.finishInitialLoad() and the loader animation on #loader.

This distinction is important when you want:

  • one animation for the initial boot
  • another animation for later route changes

The transition's enter completion is also the point where ReactWP advances the shell lifecycle keys. This lets header/footer effects recreate after the incoming page is mounted instead of during the outgoing state.

Customization​

Use config/configurePageTransition.js to override the default route animation.

Example:

import { PageTransitionAnimation } from './PageTransition';

export const configurePageTransition = () => {

PageTransitionAnimation
.setLeave(({ gsap }) => {
return gsap.to('#viewport', {
duration: 0.2,
opacity: 0,
pointerEvents: 'none'
});
})
.setEnter(({ gsap }) => {
return gsap.to('#viewport', {
duration: 0.2,
opacity: 1,
pointerEvents: 'initial'
});
});

};

The starter restores its default transition behavior before that configuration file runs, so a project only needs to describe its overrides.

Reduced Motion​

The transition runtime also supports reduced motion handling through its immediate fallbacks.

If the user prefers reduced motion, the runtime can apply immediate state changes instead of a full tween.

Projects can provide those immediate fallbacks through the second argument of:

  • PageTransitionAnimation.setLeave(animation, immediate)
  • PageTransitionAnimation.setEnter(animation, immediate)