diff --git a/examples/react/view-transitions/src/routes/posts.route.tsx b/examples/react/view-transitions/src/routes/posts.route.tsx
index 88296c3c54a..983d2943907 100644
--- a/examples/react/view-transitions/src/routes/posts.route.tsx
+++ b/examples/react/view-transitions/src/routes/posts.route.tsx
@@ -1,6 +1,10 @@
-import { createFileRoute } from '@tanstack/react-router'
+import {
+ Link,
+ Outlet,
+ createFileRoute,
+ useRouter,
+} from '@tanstack/react-router'
import * as React from 'react'
-import { Link, Outlet } from '@tanstack/react-router'
import { fetchPosts } from '../posts'
export const Route = createFileRoute('/posts')({
@@ -10,6 +14,7 @@ export const Route = createFileRoute('/posts')({
function PostsLayoutComponent() {
const posts = Route.useLoaderData()
+ const router = useRouter()
return (
@@ -25,8 +30,30 @@ function PostsLayoutComponent() {
}}
className="block py-1 text-blue-600 hover:opacity-75"
activeProps={{ className: 'font-bold underline' }}
- // see styles.css for 'warp' transition
- viewTransition={{ types: ['warp'] }}
+ // see styles.css for 'warp' and 'warp-backwards' transition
+ viewTransition={{
+ types: ({ fromLocation, toLocation }) => {
+ const fromRoute = router
+ .matchRoutes(fromLocation?.pathname ?? '/')
+ .find((entry) => entry.routeId === '/posts/$postId')
+ const toRoute = router
+ .matchRoutes(toLocation?.pathname ?? '/')
+ .find((entry) => entry.routeId === '/posts/$postId')
+
+ const fromIndex = Number(fromRoute?.params.postId)
+ const toIndex = Number(toRoute?.params.postId)
+
+ if (
+ Number.isNaN(fromIndex) ||
+ Number.isNaN(toIndex) ||
+ fromIndex === toIndex
+ ) {
+ return false // no transition
+ }
+
+ return fromIndex > toIndex ? ['warp-backwards'] : ['warp']
+ },
+ }}
>
{post.title.substring(0, 20)}
diff --git a/examples/react/view-transitions/src/styles.css b/examples/react/view-transitions/src/styles.css
index 818667133d4..172cf34be99 100644
--- a/examples/react/view-transitions/src/styles.css
+++ b/examples/react/view-transitions/src/styles.css
@@ -87,6 +87,16 @@ html:active-view-transition-type(warp) {
}
}
+html:active-view-transition-type(warp-backwards) {
+ &::view-transition-old(post) {
+ animation: 400ms ease-out both warp-out-backwards;
+ }
+
+ &::view-transition-new(post) {
+ animation: 400ms ease-out both warp-in-backwards;
+ }
+}
+
@keyframes warp-out {
from {
opacity: 1;
@@ -112,3 +122,29 @@ html:active-view-transition-type(warp) {
transform: scale(1) rotate(0deg);
}
}
+
+@keyframes warp-in-backwards {
+ from {
+ opacity: 0;
+ filter: blur(15px) brightness(1.8);
+ transform: scale(0.9) rotate(45deg);
+ }
+ to {
+ opacity: 1;
+ filter: blur(0) brightness(1);
+ transform: scale(1) rotate(0deg);
+ }
+}
+
+@keyframes warp-out-backwards {
+ from {
+ opacity: 1;
+ filter: blur(0) brightness(1);
+ transform: scale(1) rotate(0deg);
+ }
+ to {
+ opacity: 0;
+ filter: blur(15px) brightness(1.8);
+ transform: scale(1.1) rotate(-90deg);
+ }
+}