Enable smooth animations between page transitions in your React Router applications using the [View Transitions API][view-transitions-api]. This feature allows you to create seamless visual transitions during client-side navigation.
## Basic View Transition
### 1. Enable view transitions on navigation
The simplest way to enable view transitions is by adding the `viewTransition` prop to your `Link`, `NavLink`, or `Form` components. This automatically wraps the navigation update in `document.startViewTransition()`.
```tsx
About
```
Without any additional CSS, this provides a basic cross-fade animation between pages.
### 2. Enable view transitions with programmatic navigation
When using programmatic navigation with the `useNavigate` hook, you can enable view transitions by passing the `viewTransition: true` option:
```tsx
import { useNavigate } from "react-router";
function NavigationButton() {
const navigate = useNavigate();
return (
);
}
```
This provides the same cross-fade animation as using the `viewTransition` prop on Link components.
For more information on using the View Transitions API, please refer to the ["Smooth transitions with the View Transition API" guide][view-transitions-guide] from the Google Chrome team.
## Image Gallery Example
Let's build an image gallery that demonstrates how to trigger and use view transitions. We'll create a list of images that expand into a detail view with smooth animations.
### 1. Create the image gallery route
```tsx filename=routes/image-gallery.tsx
import { NavLink } from "react-router";
export const images = [
"https://remix.run/blog-images/headers/the-future-is-now.jpg",
"https://remix.run/blog-images/headers/waterfall.jpg",
"https://remix.run/blog-images/headers/webpack.png",
// ... more images ...
];
export default function ImageGalleryRoute() {
return (
Image List
{images.map((src, idx) => (
Image Number {idx}
))}
);
}
```
### 2. Add transition styles
Define view transition names and animations for elements that should transition smoothly between routes.
```css filename=app.css
/* Layout styles for the image grid */
.image-list > div {
display: grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 10px;
}
.image-list h1 {
font-size: 2rem;
font-weight: 600;
}
.image-list img {
max-width: 100%;
contain: layout;
}
.image-list p {
width: fit-content;
}
/* Assign transition names to elements during navigation */
.image-list a.transitioning img {
view-transition-name: image-expand;
}
.image-list a.transitioning p {
view-transition-name: image-title;
}
```
### 3. Create the image detail route
The detail view needs to use the same view transition names to create a seamless animation.
```tsx filename=routes/image-details.tsx
import { Link } from "react-router";
import { images } from "./home";
import type { Route } from "./+types/image-details";
export default function ImageDetailsRoute({
params,
}: Route.ComponentProps) {
return (
Back
Image Number {params.id}
);
}
```
### 4. Add matching transition styles for the detail view
```css filename=app.css
/* Match transition names from the list view */
.image-detail h1 {
font-size: 2rem;
font-weight: 600;
width: fit-content;
view-transition-name: image-title;
}
.image-detail img {
max-width: 100%;
contain: layout;
view-transition-name: image-expand;
}
```
## Advanced Usage
You can control view transitions more precisely using either render props or the `useViewTransitionState` hook.
### 1. Using render props
```tsx filename=routes/image-gallery.tsx
{({ isTransitioning }) => (
<>
Image Number {idx}
>
)}
```
### 2. Using the `useViewTransitionState` hook
```tsx filename=routes/image-gallery.tsx
function NavImage(props: { src: string; idx: number }) {
const href = `/image/${props.idx}`;
// Hook provides transition state for specific route
const isTransitioning = useViewTransitionState(href);
return (