Documentation
Build your first Route Transition
Connect a destination, Preset, Provider, and Link for coordinated navigation.This guide shows how the pieces of a Route Transition connect. Use the example as a starting point, then adapt the temporary UI and animation to your application.
Before you begin
You need a Next.js App Router project that meets Segue's exact requirements and has @humaan/segue installed. The example uses the browser's Web Animations API, but you can use another animation library.
How the pieces connect
The manifest assigns a Preset to the destination. The Preset defines the Cover. The Provider makes both available across route changes. Segue.Link starts coordinated navigation.
1. Define the destination
Keep the Preset, rendition, and Transition Image prop types in one server-safe module. Both the manifest and client API will use these types, which prevents their generic parameters from drifting apart.
// lib/segue-types.ts
export type PresetName = "project-cover";
export type RenditionData = {
readonly src: string;
readonly width: number;
readonly height: number;
};
export type TransitionImageProps = {
readonly alt: string;
readonly className?: string;
};Create the destination route:
// app/projects/field-study/page.tsx
export default function FieldStudyPage() {
return <h1>Field study</h1>;
}Then assign the project-cover Preset to its exact path. The required imagesByRole object is empty because this Cover doesn't use a Transition Image.
// lib/segue-manifest.ts
import { defineManifest } from "@humaan/segue";
import type { PresetName, RenditionData } from "./segue-types";
export const segueManifest = defineManifest<PresetName, RenditionData>({
routes: [
{
path: "/projects/field-study",
preset: "project-cover",
imagesByRole: {},
},
],
});2. Create your Segue API
Call createSegue once with the same shared types. Export this single object for the rest of your client code.
// components/segue.tsx
"use client";
import { createSegue } from "@humaan/segue/client";
import type {
PresetName,
RenditionData,
TransitionImageProps,
} from "@/lib/segue-types";
export const Segue = createSegue<
PresetName,
RenditionData,
TransitionImageProps
>();3. Define a Preset
Define the temporary UI and Cover animation. Every Route-Transition Preset has four required properties:
imageRoleslists the Transition Image roles the Preset needs.reducedMotiontells Segue whether to run or skip the Preset when the visitor prefers reduced motion.renderreturns the temporary UI.animateruns the Cover after Segue adds that UI to the document.
The animate callback receives root, the wrapper around the rendered UI, and navigation.signal, which aborts when Segue stops the transition. Pass the animation and signal to waitForAnimation; it handles native animation cancellation, including an already-aborted signal.
// components/route-transitions.tsx
"use client";
import type { ComponentProps, ReactNode } from "react";
import { waitForAnimation } from "@humaan/segue/client";
import { segueManifest } from "@/lib/segue-manifest";
import { Segue } from "./segue";
const presets = {
"project-cover": Segue.definePreset({
imageRoles: [],
reducedMotion: "skip",
render: () => <div className="project-cover" />,
animate: async ({ root, navigation }) => {
const cover = root.querySelector<HTMLElement>(".project-cover");
if (!cover) return;
const animation = cover.animate(
[
{ transform: "translateX(-100%)" },
{ transform: "translateX(0)" },
],
{
duration: 600,
easing: "cubic-bezier(.76, 0, .24, 1)",
fill: "forwards",
},
);
await waitForAnimation(animation, navigation.signal);
},
}),
} satisfies ComponentProps<typeof Segue.Provider>["presets"];The fill: "forwards" option makes the Cover's final state durable while Segue waits for route commit. Without it, the panel can return to its initial off-screen style after the animation finishes but before the destination appears.
4. Mount the Provider
Append this component to components/route-transitions.tsx. Mount only one Provider per browser window in a layout that remains mounted across the source and destination routes.
export function RouteTransitions({ children }: { readonly children: ReactNode }) {
return (
<Segue.Provider manifest={segueManifest} presets={presets}>
{children}
</Segue.Provider>
);
}Wrap your application in the root layout:
// app/layout.tsx
import type { ReactNode } from "react";
import { RouteTransitions } from "@/components/route-transitions";
export default function RootLayout({ children }: { readonly children: ReactNode }) {
return (
<html lang="en">
<body>
<RouteTransitions>{children}</RouteTransitions>
</body>
</html>
);
}Segue throws an error if another Provider mounts in the same browser window.
5. Use Segue.Link
Render Segue.Link on the source page for the coordinated navigation. It accepts the normal Next.js Link and anchor props.
// app/page.tsx
"use client";
import { Segue } from "@/components/segue";
export default function HomePage() {
return (
<main>
<h1>Projects</h1>
<Segue.Link href="/projects/field-study">
View the field study
</Segue.Link>
</main>
);
}Because the manifest assigns project-cover to /projects/field-study, Segue runs that Preset before following this link. A Segue.Link to a path outside the manifest still navigates without a Preset.
6. Style the Cover
Make the Cover fill the viewport and appear above the current route:
.project-cover {
position: fixed;
inset: 0;
z-index: 100;
pointer-events: none;
background: #d7ff64;
transform: translateX(-100%);
}Start your application and select View the field study. The green panel crosses the current route before /projects/field-study appears.
Next steps
- Add Transition Images to render destination media inside a Preset.
- Use a Route-Transition Override for a source-specific interaction.
- Integrate Segue into a production route shell for scroll, interaction, focus, and Destination Entrance behavior.