Page Transitions

Route-based page transition system

Configuration Interface

SsgoiConfig

interface SsgoiConfig {
  transitions: Array<{
    from: string; // Source route pattern
    to: string; // Destination route pattern
    transition: SggoiTransition;
    symmetric?: boolean; // Auto-generate bidirectional transition
  }>;
  defaultTransition?: SggoiTransition;
}

Basic Configuration

import { Ssgoi } from "@ssgoi/react";
import { fade, slide } from "@ssgoi/react/view-transitions";

const config = {
  defaultTransition: fade(),
  transitions: [
    { from: "/", to: "/about", transition: slide({ direction: "left" }) },
    { from: "/about", to: "/", transition: slide({ direction: "right" }) },
  ],
};

<Ssgoi config={config}>{children}</Ssgoi>;

Route Matching Rules

Pattern Types

  1. Exact Match: /home → Matches exactly with /home
  2. Wildcard Suffix: /products/* → Matches /products/123
  3. Full Wildcard: * → Matches all routes

Matching Priority

More specific patterns take precedence:

transitions: [
  // 1st priority: Exact match
  { from: "/blog/post-1", to: "/blog/post-2", transition: slide() },

  // 2nd priority: Wildcard match
  { from: "/blog/*", to: "/blog/*", transition: fade() },

  // 3rd priority: defaultTransition
];

Symmetric Option

Automatically generates bidirectional transitions:

{
  from: '/home',
  to: '/about',
  transition: fade(),
  symmetric: true  // Automatically generates reverse transition
}

// The above configuration works as follows:
// /home → /about: fade
// /about → /home: fade (auto-generated)

View Transition Structure

View Transition follows the same structure as Element Transition:

interface ViewTransition {
  in?: (
    element: HTMLElement,
    context?: SggoiTransitionContext
  ) => TransitionConfig;
  out?: (
    element: HTMLElement,
    context?: SggoiTransitionContext
  ) => TransitionConfig;
}
  • out: Applied to from page (exiting page)
  • in: Applied to to page (entering page)

Context Object

The scroll difference between the previous page and current page is passed as the second argument to View Transition:

interface SggoiTransitionContext {
  scrollOffset: {
    x: number; // Scroll X difference between previous and current page
    y: number; // Scroll Y difference between previous and current page
  };
}

// Example: Scroll-aware transition
const scrollAwareTransition = {
  in: (element, context) => {
    const { scrollOffset } = context;
    return {
      prepare: (el) => {
        // Start by moving by the scroll difference
        el.style.transform = `translateY(${-scrollOffset.y}px)`;
      },
      tick: (progress) => ({
        // Return to original position
        transform: `translateY(${-scrollOffset.y * (1 - progress)}px)`,
      }),
    };
  },
};

SsgoiTransition Component

Wrapper component that wraps each page:

<SsgoiTransition id="/page-path">
  <PageContent />
</SsgoiTransition>
  • id: Identifier used for route matching
  • This ID is matched against from/to patterns in config

Operation Flow

  1. Route Change Detection: Router changes route
  2. Pattern Matching: Find transition to apply using from/to patterns
  3. Out Animation: Apply out transition to current page
  4. Synchronization: Wait for out and in animation preparation
  5. In Animation: Apply in transition to new page
  6. Completion: Clean up when both animations complete

Practical Examples

Hierarchical Navigation

const config = {
  transitions: [
    // List → Detail
    {
      from: "/products",
      to: "/products/*",
      transition: scale({ from: 0.95 }),
      symmetric: true, // Auto-handle Detail → List too
    },

    // Tab navigation
    { from: "/tab1", to: "/tab2", transition: slide({ direction: "left" }) },
    { from: "/tab2", to: "/tab3", transition: slide({ direction: "left" }) },
    { from: "/tab3", to: "/tab2", transition: slide({ direction: "right" }) },
    { from: "/tab2", to: "/tab1", transition: slide({ direction: "right" }) },
  ],
};