Skip to content

Commit 0da5831

Browse files
docs: add view transition "how to" (#12247)
* Add view transition how to * Minor tweaks
1 parent e6dd000 commit 0da5831

File tree

1 file changed

+202
-3
lines changed

1 file changed

+202
-3
lines changed

docs/framework/how-to/view-transitions.md

Lines changed: 202 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,205 @@ title: View Transitions
44

55
# View Transitions
66

7-
<docs-warning>
8-
This document is a work in progress. There's not much to see here (yet).
9-
</docs-warning>
7+
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.
8+
9+
## Basic View Transition
10+
11+
👉 **Enable view transitions on navigation**
12+
13+
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()`.
14+
15+
```tsx
16+
<Link to="/about" viewTransition>
17+
About
18+
</Link>
19+
```
20+
21+
Without any additional CSS, this provides a basic cross-fade animation between pages.
22+
23+
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.
24+
25+
## Image Gallery Example
26+
27+
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.
28+
29+
👉 **Create the image gallery route**
30+
31+
```tsx filename=routes/image-gallery.tsx
32+
import { NavLink } from "react-router";
33+
34+
export const images = [
35+
"https://remix.run/blog-images/headers/the-future-is-now.jpg",
36+
"https://remix.run/blog-images/headers/waterfall.jpg",
37+
"https://remix.run/blog-images/headers/webpack.png",
38+
// ... more images ...
39+
];
40+
41+
export default function ImageGalleryRoute() {
42+
return (
43+
<div className="image-list">
44+
<h1>Image List</h1>
45+
<div>
46+
{images.map((src, idx) => (
47+
<NavLink
48+
key={src}
49+
to={`/image/${idx}`}
50+
viewTransition // Enable view transitions for this link
51+
>
52+
<p>Image Number {idx}</p>
53+
<img
54+
className="max-w-full contain-layout"
55+
src={src}
56+
/>
57+
</NavLink>
58+
))}
59+
</div>
60+
</div>
61+
);
62+
}
63+
```
64+
65+
👉 **Add transition styles**
66+
67+
Define view transition names and animations for elements that should transition smoothly between routes.
68+
69+
```css filename=app.css
70+
/* Layout styles for the image grid */
71+
.image-list > div {
72+
display: grid;
73+
grid-template-columns: repeat(4, 1fr);
74+
column-gap: 10px;
75+
}
76+
77+
.image-list h1 {
78+
font-size: 2rem;
79+
font-weight: 600;
80+
}
81+
82+
.image-list img {
83+
max-width: 100%;
84+
contain: layout;
85+
}
86+
87+
.image-list p {
88+
width: fit-content;
89+
}
90+
91+
/* Assign transition names to elements during navigation */
92+
.image-list a.transitioning img {
93+
view-transition-name: image-expand;
94+
}
95+
96+
.image-list a.transitioning p {
97+
view-transition-name: image-title;
98+
}
99+
```
100+
101+
👉 **Create the image detail route**
102+
103+
The detail view needs to use the same view transition names to create a seamless animation.
104+
105+
```tsx filename=routes/image-details.tsx
106+
import { Link } from "react-router";
107+
import { images } from "./home";
108+
import type { Route } from "./+types.image-details";
109+
110+
export default function ImageDetailsRoute({
111+
params,
112+
}: Route.ComponentProps) {
113+
return (
114+
<div className="image-detail">
115+
<Link to="/" viewTransition>
116+
Back
117+
</Link>
118+
<h1>Image Number {params.id}</h1>
119+
<img src={images[Number(params.id)]} />
120+
</div>
121+
);
122+
}
123+
```
124+
125+
👉 **Add matching transition styles for the detail view**
126+
127+
```css filename=app.css
128+
/* Match transition names from the list view */
129+
.image-detail h1 {
130+
font-size: 2rem;
131+
font-weight: 600;
132+
width: fit-content;
133+
view-transition-name: image-title;
134+
}
135+
136+
.image-detail img {
137+
max-width: 100%;
138+
contain: layout;
139+
view-transition-name: image-expand;
140+
}
141+
```
142+
143+
## Advanced Usage
144+
145+
You can control view transitions more precisely using either render props or the `useViewTransitionState` hook.
146+
147+
👉 **Using render props**
148+
149+
```tsx filename=routes/image-gallery.tsx
150+
<NavLink to={`/image/${idx}`} viewTransition>
151+
{({ isTransitioning }) => (
152+
<>
153+
<p
154+
style={{
155+
viewTransitionName: isTransitioning
156+
? "image-title"
157+
: "none",
158+
}}
159+
>
160+
Image Number {idx}
161+
</p>
162+
<img
163+
src={src}
164+
style={{
165+
viewTransitionName: isTransitioning
166+
? "image-expand"
167+
: "none",
168+
}}
169+
/>
170+
</>
171+
)}
172+
</NavLink>
173+
```
174+
175+
👉 **Using the `useViewTransitionState` hook**
176+
177+
```tsx filename=routes/image-gallery.tsx
178+
function NavImage(props: { src: string; idx: number }) {
179+
const href = `/image/${props.idx}`;
180+
// Hook provides transition state for specific route
181+
const isTransitioning = useViewTransitionState(href);
182+
183+
return (
184+
<Link to={href} viewTransition>
185+
<p
186+
style={{
187+
viewTransitionName: isTransitioning
188+
? "image-title"
189+
: "none",
190+
}}
191+
>
192+
Image Number {props.idx}
193+
</p>
194+
<img
195+
src={props.src}
196+
style={{
197+
viewTransitionName: isTransitioning
198+
? "image-expand"
199+
: "none",
200+
}}
201+
/>
202+
</Link>
203+
);
204+
}
205+
```
206+
207+
[view-transitions-api]: https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition
208+
[view-transitions-guide]: https://developer.chrome.com/docs/web-platform/view-transitions

0 commit comments

Comments
 (0)