SSGOI

Quick start

One provider file, plus one edit to the layout you already have, and your first page transition runs.

Setting up with an AI agent? Give it this file.

One package per framework. This quick start uses React and Next.js; the equivalent setup for every other stack is in Frameworks.

Next.js App Router setup

One provider file, plus one edit to your layout. The route boundary is included.

  1. Create the provider

    One rule is enough to start: drill() everywhere except the home route. It is the most visible transition, which makes step 4 unambiguous.

    // app/ssgoi-provider.tsx
    "use client";
    
    import { type ReactNode } from "react";
    import { Ssgoi } from "@ssgoi/react";
    import { drill } from "@ssgoi/react/view-transitions";
    
    const config = {
      transitions: [{ on: "/**", except: "/", transition: drill() }],
    };
    
    export function SsgoiProvider({ children }: { children: ReactNode }) {
      return <Ssgoi config={config}>{children}</Ssgoi>;
    }

    The provider and shipped boundary are client components. SSGOI reads and moves real DOM nodes, and usePathname is read inside the shipped boundary. The pages passed into it can stay server components.

    transitions also accepts a function of device context — the usual way to give phones and desktops different motion.

    import { drill, fade } from "@ssgoi/react/view-transitions";
    
    const config = {
      transitions: ({ isMobile }) =>
        isMobile
          ? [{ on: "/**", except: "/", transition: drill() }]
          : [{ priority: -100, on: "/**", transition: fade() }],
    };

    priority defaults to 0, so -100 parks that rule below every other one as a last resort — Route rules has the rest of the resolution order. isMobile is true when the scroll container is narrower than 768px, re-measured when it resizes. SSGOI calls your function once per isMobile value and caches the result, so keep it pure.

    Define config outside the component. A new object on every render rebuilds the engine and loses its saved scroll positions.

  2. Import the route boundary

    The key is what makes the framework throw the old page away — SSGOI reacts to the framework destroying and rebuilding the routed node. data-ssgoi-transition is just the label your rules match against.

    import { SsgoiRouteBoundary } from "@ssgoi/react/nextjs";
    
    <SsgoiRouteBoundary>{children}</SsgoiRouteBoundary>

    Next.js is an optional peer, loaded only by this subpath. If the wrong part of the screen moves, adjust the boundary lifetime — Route boundaries shows how to move it up or down the tree.

  3. Assemble them in the layout

    This is the one edit to a file you already have. The element around <Ssgoi> needs three classes; they hold the leaving page in place while it animates out.

    // app/layout.tsx
    import { type ReactNode } from "react";
    import { SsgoiProvider } from "./ssgoi-provider";
    import { SsgoiRouteBoundary } from "@ssgoi/react/nextjs";
    
    export default function RootLayout({ children }: { children: ReactNode }) {
      return (
        <html lang="en">
          <body>
            <main className="relative z-0 min-h-dvh overflow-x-clip">
              <SsgoiProvider>
                <SsgoiRouteBoundary>{children}</SsgoiRouteBoundary>
              </SsgoiProvider>
            </main>
          </body>
        </html>
      );
    }
    ClassWhy it is there
    relativeThe leaving page is put back into the DOM with position: absolute, so it lands relative to the nearest positioned ancestor. Without this it jumps to the top of the document.
    z-0Gives the wrapper its own stacking context, so the layers a transition creates stay inside your shell instead of covering a fixed header. Transitions never use a negative z-index, so the leaving page cannot fall behind your background.
    overflow-x-clipStops a horizontal scrollbar from flashing while slide, drill or strip move a page off-screen. Use clip, not hidden — overflow-x: hidden turns the wrapper into the scroll container, and scroll restore then targets the wrong element.

    Without Tailwind, write position: relative; z-index: 0; min-height: 100dvh; overflow-x: clip. If the leaving page appears in the wrong place or slides under your header, Layout shell explains which of the three is missing.

  4. Run it

    Start the app and navigate. Two things tell you the wiring is right.

    1. From / to any other page, the new page slides in from the right.
    2. Back to /, the page slides out to the right.

    If nothing moves, or the wrong region moves, the cause is almost in the layout or boundary placement: check Layout shell for the wrapper classes and Route boundaries for where the key sits.

That is the whole setup. This boundary remounts the entire routed area on every navigation, which is correct until you need something to stay put — a bottom nav that survives page changes, for instance. That is Persistent layouts.

Reference templates

Each template is a runnable app already wired the recommended way for its router. Clone one and read its provider, boundary and layout files, or copy the pieces you need.

Router integrations other than Next.js are experimental APIs.

Router helpers are grouped under their rendering framework. Qwik keeps the key and marker on the page root; Angular offers a structural directive that recreates that root when its key changes. All templates ↗

Next: pick the motion your product actually needs in Transitions.