Skip to content

Last updated: First published:

Global Flow & Events

Astro’s view transition support is described in the Astro Docs↗. The following sections give additional details on process and events.

Astro’s view transition feature provides cross document transitions. It replace the full page load of normal browser navigation with a smooth animation while changing pages. Then it updates the browser history and the window’s scroll position. In the end, it works like normal navigation, but it feels more like the slick transitions within a single page app.

Astro’s <ViewTransitions /> use the View Transition API for browsers that support it natively. For other browsers, Astro provides a simulation.

Soft Load

When Astro introduced cross document view transitions, only Chrome supported real cross document view transitions and only after this experimental feature was explicitly enabled by the user. Support for cross document view transitions as defined in the Level 2 View Transition API is still in its infancy.

For browsers that do not have native support of the View Transition API, or only for Level 1, it is impossible to implement cross document view transitions without replacing the typical full page load. Instead a mechanism is required that allows to continue the execution of the code and to keep the state across the page switch. For Astro, this mechanism is also sometimes referred to as soft load of new contents. There are some fundamental differences between the soft load and the typical full page load.

The most important difference is that a full page load completely resets the state of the window object before it loads the new page. This includes resetting all variables, the DOM at window.document, all scripts and the module loader. In contrast, Astro’s soft load retains all state and attempts to change it so it corresponds to the target state.

Triggers

There are four types of actions that trigger Astro’s View Transitions:

  1. Clicking on a link (HTML <a> Element, SVG Anchor <a> and <map><area>)
  2. Submitting a <form>
  3. Pressing a browsers buttons for history navigation, using according keyboard shortcuts, or calls to history functions back(), forward(), or go()
  4. Calling the navigate() function, which is provided by astro:transitions/client

Customization of the view transition is supported by Astro’s transition events and a view transition object with three promises that resolve or reject at different points during the transition. For details see the View Transition documentation↗ on MDN. Users can use the events and the promises to trigger custom code.

Processing Flow

Processing of the view transition flow begins with a preparation phase that by default loads the DOM of the target page. Then the actual view transition begins, which takes a screenshot of the current view (green line), swaps the current DOM with the contents of the loaded DOM and then starts the animations that remove the old image and in parallel bring in the new image (red line).

Structure of the View Transition Router

This is the behavior for browsers that have native view transition support. The startViewTransition(../flow-events/) function and the view transition promises are part of the View Transition API.

For browsers that have no native support for view transitions, things happen slightly different. The exit animation to remove the old page happens on the green arrow, the enter animation to bring in the new image happens on the red arrow. The core functionality of the startViewTransition() function and the view transition promises are provided by Astro.

In the completion phase, the newly added scripts are executed, the page title of the new route is announced for users of assistive technologies and some clean-up work is carried out at the end.

Step by Step

The single steps of the processing are as follows:

  1. Detect and cancel a previous view transition if it is still running
  2. Fallback to a full page load for a cross origin navigation (no CORS)
  3. Detection and handling of a same-page navigation, which does not trigger view transitions
  4. Trigger astro:before-preparation event e
  5. Fallback to a full page load if e.defaultPrevented is true
  6. Start e.loader() and wait for end of asynchronous processing
  7. Trigger astro:after-preparation event
  8. Simulation only: start and wait for end of exit animations
  9. Native API: Call startViewTransition() with steps 9. - 12. as the update callback. Starts exit and enter animations in parallel once update is done.
  10. Trigger astro:before-swap event e

  11. Run e.swap()

  12. Update browser history and scroll position

  13. Trigger astro:after-swap event

  14. Simulation only: start entry animations
  15. Start and await the loading (or error during loading) of new scripts
  16. Trigger astro:page-load event
  17. Announce route to assistive technologies
  18. Wait for all animations to finish and clean up

For details about the customizable loader() and swap() functions see below and here

Events

The yellow blocks in the diagram above mark the positions in Astro’s navigation processing at which events are triggered. There are five events.

  • astro:before-preparation and astro:after-preparation at the beginning and end of the preparation phase.
  • astro:before-swap and astro:after-swap at the beginning and end of the swap phase.
  • astro:page-load during the closing phase.

The astro:after- events and the astro:page-load event are standard Event objects. Their main purpose is to allow the user code to react to the completion of a processing phase.

The astro:before-* events provide navigation-specific properties that show details of the processing. Some of these properties are even writable to give users control over the behavior of navigation processing.

All five events fire on window.document.

astro:before-preparation

1
readonly from: URL // The page where the navigation started
2
to: URL // The destination of the navigation.
3
direction: Direction | string // The values directly supported by Astro are 'forward' and 'backward', but this can be extended to other values. This property is writable.
4
readonly navigationType: NavigationTypeString // 'traverse' | 'push' | 'replace'
5
readonly sourceElement: Element // If triggered by a link navigation, the anchor element. If triggered by form submission, the submitter (and if submitter is null, the form element). Can also be set via the sourceElement property of the options parameter on a call to navigate()
6
readonly info: any // If the transition was initiated by a call to navigate(), the value of options.info. Set to an empty object if undefined.
7
newDocument: Document // The DOM to be transitioned to. This can be an empty DOM if swap() manipulates the current DOM in place.
8
signal: AbortSignal // The AbortController signal of the navigation. The defaultLoader uses this to abort ongoing fetch operations. Any activity that is to be aborted if a new navigation starts before the previous one ends can attach itself to this signal.
9
readonly formData: FormData // Automatically filled in if the navigation was triggered by a form. If the navigation was triggered by a call to navigate(), the value of options.formData.
10
loader: () => Promise<void> // A function that sets event.newDocument to the contents of event.to.

While the event listener code must run synchronously, the loader function will perform asynchronous actions.

The loader property initially holds Astro’s built-in implementation for loading the contents of event.to into event.newDocument. An event listener might override the value of the loader property to define a completely independent implementation.

Typeastro:before-preparation
TypeScript TypeTransitionBeforePreparationEvent
Cancelableyes

astro:before-swap

Most of the properties of the astro:before-swap event are identical to those of the astro:before-preparation event. The differences are:

  • direction is readonly in astro:before-swap
  • formData and loader are not defined in astro:before-swap
  • the astro:before-swapevent offers two additional properties:
1
swap: () => void // Initially, Astro's built-in implementation of the swap() operation. The task of the swap operation is to update the current DOM, typically to reflect the contents of event.newDocument.
2
readonly viewTransition: ViewTransition // The object returned by startViewTransition().

For documentation on startViewTransition visit mdn↗. It is possible to override the built-in implementation of swap() by assigning to the swap property. Other than loader, swap does not support asynchronous actions. Browser implementations of view transition put a rather rigid timeout on the code that can run during swap. Long running code should be moved to the loader callback.

Typeastro:before-swap
TypeScript TypeTransitionBeforeSwapEvent
Cancelableno

The navigate function gives you programmatic access to view transitions. When you call it, it starts the processing flow described above.

The function accepts two parameters: the URL to be navigated to and an optional option parameter.

1
type Options = {
2
history?: 'auto' | 'push' | 'replace';
3
state?: any;
4
info?: any;
5
formData?: FormData;
6
sourceElement?: Element;
7
};
8
async function navigate(href: string, options?: Options);

The function and its options are inspired by the Navigation API’s navigate()↗.

  • history controls whether the navigate() will change the browser’s history by calling history.pushState() or history.replaceState(). The values of push and auto are equivalent because the differences described as NotSupportedError at https://developer.mozilla.org/en-US/docs/Web/API/Navigation/navigate#exceptions↗ can not be triggered with Astro.
  • state can be an arbitrary value that will be written into the browser’s history state.
  • info, formData and sourceElement: These are values that can be accessed in the astro:before-* events.

The function returns a promise that fulfills when the new page got swapped in and the history entry got written. It does not wait for the animation of the view transition.