CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-astro

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

transitions.mddocs/

View Transitions

Astro's view transitions provide smooth page transitions with built-in animations, programmatic navigation, and customizable transition effects using the View Transitions API.

Capabilities

ClientRouter Component

Enables client-side routing with view transitions.

---
import { ClientRouter } from 'astro:transitions';
---

<html>
  <head>
    <ClientRouter fallback="animate" />
  </head>
  <body>
    <!-- Your content -->
  </body>
</html>

Props:

interface ClientRouterProps {
  /**
   * Fallback behavior for browsers without View Transitions API
   * - 'animate': Use animation fallback
   * - 'swap': Instant swap without animation
   * - 'none': No client-side routing
   * @default 'animate'
   */
  fallback?: 'animate' | 'swap' | 'none';
}

Migrating from ViewTransitions to ClientRouter

The ViewTransitions component has been deprecated in favor of ClientRouter. The migration is straightforward with no breaking changes to functionality.

Before (Deprecated):

---
import { ViewTransitions } from 'astro:transitions';
---
<html>
  <head>
    <ViewTransitions fallback="animate" />
  </head>
</html>

After (Current):

---
import { ClientRouter } from 'astro:transitions';
---
<html>
  <head>
    <ClientRouter fallback="animate" />
  </head>
</html>

What Changed:

  • Component name: ViewTransitionsClientRouter
  • All props remain the same (fallback)
  • Functionality is identical
  • Import source remains astro:transitions

Why the change: The new name better reflects that this component enables client-side routing, not just view transitions.

Transition Animations

Slide Transition

Creates a slide transition animation.

/**
 * Creates slide transition animations
 * @param options - Animation options
 * @returns Directional animation configuration
 */
function slide(options?: {
  duration?: string | number;
}): TransitionDirectionalAnimations;

interface TransitionDirectionalAnimations {
  forwards: TransitionAnimationPair;
  backwards: TransitionAnimationPair;
}

interface TransitionAnimationPair {
  old: AnimationKeyframes | AnimationKeyframes[];
  new: AnimationKeyframes | AnimationKeyframes[];
}
---
import { slide } from 'astro:transitions';
---

<div transition:animate={slide({ duration: '0.3s' })}>
  Content with slide transition
</div>

Fade Transition

Creates a fade transition animation.

/**
 * Creates fade transition animations
 * @param options - Animation options
 * @returns Directional animation configuration
 */
function fade(options?: {
  duration?: string | number;
}): TransitionDirectionalAnimations;
---
import { fade } from 'astro:transitions';
---

<div transition:animate={fade({ duration: 200 })}>
  Content with fade transition
</div>

Create Animation Scope

Creates a scoped animation name for view transitions.

/**
 * Creates a scoped animation name
 * @param name - Animation name
 * @param options - Animation options
 * @returns Scoped animation name
 */
function createAnimationScope(
  name: string,
  options?: AnimationOptions
): string;

Programmatic Navigation

Navigate Function

Programmatically navigate to a different page with view transitions.

/**
 * Programmatically navigate to a URL
 * Available from astro:transitions/client
 * @param href - Target URL
 * @param options - Navigation options
 * @returns Promise resolving when navigation completes
 */
function navigate(href: string, options?: Options): Promise<void>;

interface Options {
  /**
   * History manipulation strategy
   * - 'auto': Use push unless navigating back
   * - 'push': Add new history entry
   * - 'replace': Replace current history entry
   * @default 'auto'
   */
  history?: 'auto' | 'push' | 'replace';

  /**
   * Form data for POST navigation
   */
  formData?: FormData;

  /**
   * State to store in history
   */
  state?: any;

  /**
   * Source element for animation origin
   */
  sourceElement?: Element;

  /**
   * Additional navigation info
   */
  info?: Record<string, any>;
}
import { navigate } from 'astro:transitions/client';

// Basic navigation
await navigate('/about');

// With options
await navigate('/contact', {
  history: 'push',
  state: { from: '/home' },
});

// POST navigation
const formData = new FormData();
formData.append('name', 'John');
await navigate('/api/submit', {
  formData,
  history: 'replace',
});

Supports View Transitions

Checks if the browser natively supports the View Transitions API.

/**
 * Whether browser natively supports View Transitions API
 */
const supportsViewTransitions: boolean;
import { supportsViewTransitions } from 'astro:transitions/client';

if (supportsViewTransitions) {
  console.log('Native view transitions supported');
} else {
  console.log('Using fallback animations');
}

Get Fallback

Gets the current fallback mode.

/**
 * Gets the current fallback mode
 * @returns Current fallback mode
 */
function getFallback(): Fallback;

type Fallback = 'animate' | 'swap' | 'none';

Transition Enabled On This Page

Checks if transitions are enabled on the current page.

/**
 * Checks if transitions are enabled on current page
 * @returns True if transitions are enabled
 */
function transitionEnabledOnThisPage(): boolean;

Transition Events

View transitions fire several lifecycle events that can be listened to.

Event Names

/**
 * Fired before fetching and preparing the new page
 */
const TRANSITION_BEFORE_PREPARATION: 'astro:before-preparation';

/**
 * Fired after preparing but before swapping DOM
 */
const TRANSITION_AFTER_PREPARATION: 'astro:after-preparation';

/**
 * Fired before swapping the DOM
 */
const TRANSITION_BEFORE_SWAP: 'astro:before-swap';

/**
 * Fired after swapping the DOM
 */
const TRANSITION_AFTER_SWAP: 'astro:after-swap';

/**
 * Fired when page is loaded (including first load)
 */
const TRANSITION_PAGE_LOAD: 'astro:page-load';

TransitionBeforePreparationEvent

class TransitionBeforePreparationEvent extends Event {
  /**
   * Function to load additional resources before transition
   */
  loader: () => Promise<void>;

  /**
   * Target URL
   */
  to: URL;

  /**
   * Source URL
   */
  from: URL;

  /**
   * Navigation direction
   */
  direction: Direction;

  /**
   * Navigation type
   */
  navigationType: NavigationTypeString;

  /**
   * Source element that triggered navigation
   */
  sourceElement: Element;

  /**
   * Additional navigation info
   */
  info: Record<string, any>;

  /**
   * The new document being prepared
   */
  newDocument: Document;

  /**
   * Abort signal for canceling transition
   */
  signal: AbortSignal;
}

type Direction = 'forward' | 'back';
type NavigationTypeString = 'traverse' | 'push' | 'replace';
import { TRANSITION_BEFORE_PREPARATION } from 'astro:transitions/client';

document.addEventListener(TRANSITION_BEFORE_PREPARATION, (event) => {
  console.log('Navigating to:', event.to.pathname);

  // Load additional resources
  event.loader(async () => {
    await fetch('/api/prepare');
  });
});

TransitionBeforeSwapEvent

class TransitionBeforeSwapEvent extends Event {
  /**
   * Target URL
   */
  to: URL;

  /**
   * Source URL
   */
  from: URL;

  /**
   * Navigation direction
   */
  direction: Direction;

  /**
   * Navigation type
   */
  navigationType: NavigationTypeString;

  /**
   * Source element
   */
  sourceElement: Element;

  /**
   * Additional navigation info
   */
  info: Record<string, any>;

  /**
   * The new document to swap in
   */
  newDocument: Document;

  /**
   * Abort signal
   */
  signal: AbortSignal;

  /**
   * View transition API object
   */
  readonly viewTransition: ViewTransition;

  /**
   * Function to perform the swap
   */
  swap: () => void;
}
import { TRANSITION_BEFORE_SWAP } from 'astro:transitions/client';

document.addEventListener(TRANSITION_BEFORE_SWAP, (event) => {
  // Customize swap behavior
  console.log('About to swap DOM');

  // Access new document before swap
  const newTitle = event.newDocument.title;
  console.log('New page title:', newTitle);
});

Event Type Guards

/**
 * Type guard for TransitionBeforePreparationEvent
 */
function isTransitionBeforePreparationEvent(
  value: any
): value is TransitionBeforePreparationEvent;

/**
 * Type guard for TransitionBeforeSwapEvent
 */
function isTransitionBeforeSwapEvent(
  value: any
): value is TransitionBeforeSwapEvent;

Swap Functions

Custom swap function implementations.

/**
 * Object containing swap function implementations
 */
const swapFunctions: Record<string, (event: TransitionBeforeSwapEvent) => void>;

Transition Directives

Astro provides several transition directives for customizing animations.

transition:name

<div transition:name="hero">
  <!-- Element with unique transition name -->
</div>

transition:animate

---
import { slide, fade } from 'astro:transitions';
---

<div transition:animate={slide()}>
  <!-- Element with slide animation -->
</div>

<div transition:animate="fade">
  <!-- Element with fade animation (built-in) -->
</div>

transition:persist

<video transition:persist>
  <!-- Element state persists across navigation -->
</video>

Usage Patterns

Basic Setup

---
// src/layouts/Layout.astro
import { ClientRouter } from 'astro:transitions';
---

<html>
  <head>
    <ClientRouter />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

Custom Transition

---
import { fade } from 'astro:transitions';
---

<article transition:animate={fade({ duration: '0.3s' })}>
  <h1 transition:name="title">{title}</h1>
  <div class="content">
    {content}
  </div>
</article>

Programmatic Navigation with Loading

import { navigate } from 'astro:transitions/client';

async function navigateWithLoading(url: string) {
  showLoadingSpinner();

  try {
    await navigate(url);
  } finally {
    hideLoadingSpinner();
  }
}

Event Handling

import {
  TRANSITION_BEFORE_PREPARATION,
  TRANSITION_AFTER_SWAP,
  TRANSITION_PAGE_LOAD,
} from 'astro:transitions/client';

// Analytics tracking
document.addEventListener(TRANSITION_PAGE_LOAD, () => {
  if (typeof gtag !== 'undefined') {
    gtag('config', 'GA_MEASUREMENT_ID', {
      page_path: location.pathname,
    });
  }
});

// Loading indicator
document.addEventListener(TRANSITION_BEFORE_PREPARATION, () => {
  document.body.classList.add('loading');
});

document.addEventListener(TRANSITION_AFTER_SWAP, () => {
  document.body.classList.remove('loading');
});

Prefetching

Prefetch Function

Programmatically prefetches pages for faster navigation.

/**
 * Prefetches a page
 * Downloads and caches page resources in advance
 * @param url - URL to prefetch
 * @param opts - Prefetch options
 */
function prefetch(
  url: string,
  opts?: PrefetchOptions
): void;

interface PrefetchOptions {
  /**
   * Prefetch strategy
   * - 'link': Use HTML link prefetch
   * - 'fetch': Use JavaScript fetch
   */
  with?: 'link' | 'fetch';

  /**
   * When to prefetch
   * - 'immediate': Prefetch immediately
   * - 'eager': Prefetch as soon as possible
   * - 'moderate': Prefetch when link becomes visible
   * - 'conservative': Prefetch on hover/focus
   */
  eagerness?: 'immediate' | 'eager' | 'moderate' | 'conservative';

  /**
   * Whether to ignore slow connections
   * @default false
   */
  ignoreSlowConnection?: boolean;
}

Usage Examples:

import { prefetch } from 'astro:prefetch';

// Prefetch a single page
await prefetch('/about');

// Prefetch multiple pages
await prefetch(['/blog', '/contact', '/products']);

// Prefetch immediately
await prefetch('/dashboard', { with: 'load' });

// Prefetch even on slow connections
await prefetch('/important-page', {
  with: 'load',
  ignoreSlowConnection: true,
});

Auto-prefetch with data attributes:

<!-- Prefetch on hover (default) -->
<a href="/about" data-astro-prefetch>About</a>

<!-- Prefetch when link is visible -->
<a href="/blog" data-astro-prefetch="visible">Blog</a>

<!-- Prefetch on page load -->
<a href="/dashboard" data-astro-prefetch="load">Dashboard</a>

<!-- Prefetch when browser is idle -->
<a href="/products" data-astro-prefetch="idle">Products</a>

Configuration:

Enable prefetching globally in astro.config.mjs:

import { defineConfig } from 'astro/config';

export default defineConfig({
  prefetch: {
    // Prefetch all links by default
    defaultStrategy: 'hover',
    // Prefetch threshold for slow connections
    prefetchAll: true,
  },
});

Module Imports

// Transitions and animations
import { ClientRouter, slide, fade, createAnimationScope } from 'astro:transitions';

// Client-side navigation
import {
  navigate,
  supportsViewTransitions,
  transitionEnabledOnThisPage,
  TRANSITION_BEFORE_PREPARATION,
  TRANSITION_AFTER_PREPARATION,
  TRANSITION_BEFORE_SWAP,
  TRANSITION_AFTER_SWAP,
  TRANSITION_PAGE_LOAD,
  type TransitionBeforePreparationEvent,
  type TransitionBeforeSwapEvent,
  type Options,
} from 'astro:transitions/client';

// Prefetching
import { prefetch, type PrefetchOptions } from 'astro:prefetch';

docs

assets.md

cli-and-build.md

configuration.md

container.md

content-collections.md

content-loaders.md

dev-toolbar.md

environment.md

i18n.md

index.md

integrations.md

middleware.md

server-actions.md

ssr-and-app.md

transitions.md

tile.json