View Transitions

Purpose and Scope

View transitions are Astro’s navigation animation layer for preserving visual continuity as a visitor moves between pages. In author-facing terms, this feature combines a client-side router, transition directives, animation presets, navigation lifecycle events, and fallback behavior for browsers that do not fully support the browser View Transition API. The public surface is intentionally small: project code imports transition utilities from astro:transitions, annotates elements with transition animation values, and listens for Astro navigation events when it needs to coordinate custom loading, swapping, or script reinitialization.

Sources: packages/astro/src/types/public/view-transitions.ts, packages/astro/src/transitions/index.ts, packages/astro/src/transitions/events.ts

The implementation model separates animation descriptions from navigation control. Animation values are plain objects or named presets, while the router lifecycle is exposed as document events such as astro:before-preparation, astro:before-swap, and astro:page-load. That separation matters because a page can customize how elements animate without taking over document loading, and an integration or script can hook the lifecycle without redefining the default transition animations. The source types also make clear that forwards and backwards navigation can use different animation pairs, which is how Astro represents direction-aware motion.

Sources: packages/astro/src/types/public/view-transitions.ts, packages/astro/src/transitions/types.ts, packages/astro/src/transitions/events.ts

Relevant Source Files

  • packages/astro/src/types/public/view-transitions.ts defines the public animation contracts, accepted transition animation values, and global document event names exposed to TypeScript users.
  • packages/astro/src/transitions/types.ts defines router-level navigation concepts: fallback strategies, direction, navigation type strings, and navigation options.
  • packages/astro/src/transitions/index.ts exports the built-in slide() and fade() helpers that return direction-aware animation definitions.
  • packages/astro/e2e/view-transitions.test.ts verifies client-side navigation behavior, browser history handling, nested link clicks, fallback to full navigation when routing is not enabled, and preload-related behavior.
  • packages/astro/src/transitions/cssesc.ts provides a vendored CSS escaping helper used by the transition system when it needs safe CSS identifiers or string output.
  • packages/astro/src/transitions/events.ts implements transition lifecycle events and the default preparation and swap hooks used by the client router runtime.

Core Primitives

The central public type is TransitionAnimation. It describes one keyframe animation by name and optional timing properties: delay, duration, easing, fillMode, and direction. A TransitionAnimationPair groups the outgoing and incoming animation definitions as old and new, and TransitionDirectionalAnimations gives separate pairs for forwards and backwards navigation. The accepted TransitionAnimationValue union includes the named values initial, slide, fade, and none, plus a fully custom directional animation object for advanced cases.

Sources: packages/astro/src/types/public/view-transitions.ts

Router behavior is described by a smaller set of navigation types. Fallback accepts none, animate, or swap, which correspond to how Astro should behave when browser support is incomplete. Direction is forward or back, while NavigationTypeString tracks whether a navigation is a push, replace, or traverse. The Options type lets router calls carry history intent, arbitrary info and state, FormData, and the originating sourceElement; the source type deliberately allows more than HTMLElement so SVG links can participate too.

Sources: packages/astro/src/transitions/types.ts

Built-in Animation Utilities

Astro’s built-in animation helpers are implemented as regular functions that return the same public TransitionDirectionalAnimations shape users can author by hand. slide({ duration }) combines fade and slide keyframes for forward navigation, with defaults such as astroFadeOut, astroSlideToLeft, astroFadeIn, and astroSlideFromRight. Its backwards definition reverses the horizontal direction with astroSlideToRight and astroSlideFromLeft. When no custom duration is supplied, forward transitions use carefully chosen durations and a small delay on the new fade-in animation.

Sources: packages/astro/src/transitions/index.ts

fade({ duration }) is simpler: it creates a single old/new animation pair using astroFadeOut and astroFadeIn, applies the same pair to both forwards and backwards navigation, and defaults to a numeric duration of 180. Both helpers use the same cubic-bezier(0.76, 0, 0.24, 1) easing and fillMode: both, so the visual presets share a consistent motion curve. Because the helpers return data rather than running animation themselves, they fit naturally into directives and custom animation values.

Sources: packages/astro/src/transitions/index.ts

---
import { fade, slide } from 'astro:transitions';
---
<main transition:animate={slide({ duration: '220ms' })}>
  <article transition:animate={fade({ duration: 180 })}>
    Smooth navigation content
  </article>
</main>

Router Lifecycle and Events

Astro exposes navigation lifecycle hooks as document events, and the public TypeScript declaration augments DocumentEventMap with those event names. Scripts can listen for astro:before-preparation, astro:after-preparation, astro:before-swap, astro:after-swap, and astro:page-load. The source implementation models the two pre-events with classes that carry navigation context, including the current and target URLs, direction, navigation type, source element, arbitrary info, the new document, and an abort signal. This gives event handlers enough information to observe or influence a navigation without depending on private router state.

Sources: packages/astro/src/types/public/view-transitions.ts, packages/astro/src/transitions/events.ts

TransitionBeforePreparationEvent is cancelable and includes formData plus a mutable loader. Its loader is bound to the event instance so customization can still call the default loading behavior with the current event context. After preparation, TransitionBeforeSwapEvent carries the active ViewTransition and a mutable swap function. The default swap delegates to Astro’s swap implementation with the prepared document, but the event shape allows advanced code to replace that behavior before the document swap occurs.

Sources: packages/astro/src/transitions/events.ts

document.addEventListener('astro:page-load', () => {
  // Reinitialize page-level client code after Astro has swapped in the new page.
});
 
document.addEventListener('astro:before-swap', (event) => {
  // Advanced integrations can inspect event.direction or wrap event.swap().
});

Runtime Safety Details

The transition system sometimes has to turn names or values into CSS-safe output. The cssesc helper is a vendored ESM implementation of the cssesc package, with options for escaping everything, treating output as an identifier, choosing quote style, and wrapping string output. It handles non-printable characters, non-ASCII code points, surrogate pairs, quotes, backslashes, identifier-leading digits, and redundant spaces after hexadecimal escapes. This is a low-level support module, but it is important for view transitions because animation names and CSS selectors must remain valid even when input contains characters that need escaping.

Sources: packages/astro/src/transitions/cssesc.ts

The event implementation also treats navigation data as inspectable state. BeforeEvent defines properties such as from, to, direction, navigationType, sourceElement, info, newDocument, and signal as enumerable, with selected fields writable when later phases may update them. That design is useful for debugging and integration code because logged events reveal their meaningful state instead of hiding it behind private fields. At the same time, the event subclasses constrain what can be changed during each phase, keeping preparation and swap responsibilities distinct.

Sources: packages/astro/src/transitions/events.ts

Testing Signals

The end-to-end test suite gives practical signals about the expected user experience. Tests start an Astro dev server against a fixtures/view-transitions/ project, warm up /one, and then use Playwright to verify navigation. A helper records browser load events so assertions can distinguish client-side routing from full page loads. Basic navigation from page one to page two updates the visible content while only recording the initial load, demonstrating that client-side routing is handling the click after the first document request.

Sources: packages/astro/e2e/view-transitions.test.ts

The same suite verifies browser history and link edge cases. A back-button test navigates from page one to page two and then calls goBack(), expecting page one content without additional full loads. Another test clicks a link with nested content, confirming that event targeting follows the containing link rather than requiring a click directly on a text node. A separate case checks navigation to a page with non-recommended headers, while another verifies that moving to a page without the router falls back to a full page navigation. Together, these tests define the boundary between enhanced client routing and normal multi-page behavior.

Sources: packages/astro/e2e/view-transitions.test.ts

Compact API Reference

NameKindSource-backed behavior
TransitionAnimationTypeScript interfaceDescribes a keyframe animation with name, optional timing, easing, fill mode, and direction fields.
TransitionAnimationPairTypeScript interfaceGroups outgoing old and incoming new animation definitions.
TransitionDirectionalAnimationsTypeScript interfaceProvides separate animation pairs for forwards and backwards navigation.
TransitionAnimationValueTypeScript unionAccepts initial, slide, fade, none, or a custom directional animation object.
FallbackType aliasAccepts none, animate, or swap.
OptionsType aliasCarries history, info, state, formData, and sourceElement for router navigations.
slide({ duration })Exported functionReturns directional fade-plus-slide animation pairs with default timing and easing.
fade({ duration })Exported functionReturns the same fade animation pair for forward and backward navigation.
astro:before-preparationDocument eventCancelable preparation event with URLs, direction, navigation type, source element, info, document, abort signal, form data, and loader.
astro:before-swapDocument eventSwap-phase event with the prepared document, ViewTransition, and mutable swap callback.
astro:page-loadDocument eventFired after Astro’s client-side navigation has loaded the new page state.

Sources: packages/astro/src/types/public/view-transitions.ts, packages/astro/src/transitions/types.ts, packages/astro/src/transitions/index.ts, packages/astro/src/transitions/events.ts

Next Steps

Use the official View Transitions guide when you are deciding where to place the router component, which elements should receive transition directives, and whether native browser transitions or Astro’s client router is the right fit. Use this page when you need to understand the source-level contracts behind those docs: the animation object shape, the built-in helpers, the lifecycle event payloads, and the tests that prove client-side navigation behavior. For related runtime topics, continue with client-side scripts, directives syntax, routing, and Astro modules reference pages.