diff --git a/.changeset/replay-view-transition-on-traversal.md b/.changeset/replay-view-transition-on-traversal.md
new file mode 100644
index 0000000000..c920e8a018
--- /dev/null
+++ b/.changeset/replay-view-transition-on-traversal.md
@@ -0,0 +1,7 @@
+---
+'@tanstack/router-core': patch
+---
+
+feat: add `replayViewTransitionOnTraversal` router option
+
+Replays the view transition a navigation opted into (`` / `navigate({ viewTransition })`) when the user later traverses that entry with the browser Back/Forward buttons. Without it, those per-navigation opt-ins are not replayed on traversal (Back/Forward fall back to `defaultViewTransition`, if set, or no transition). Replay is symmetric (`A→B` plays on both back and forward). Opt-in, kept in-memory so a functional `types` survives, and does not affect `defaultViewTransition`.
diff --git a/docs/router/api/router/RouterOptionsType.md b/docs/router/api/router/RouterOptionsType.md
index 7127e1191e..d727ba4fea 100644
--- a/docs/router/api/router/RouterOptionsType.md
+++ b/docs/router/api/router/RouterOptionsType.md
@@ -200,6 +200,13 @@ const router = createRouter({
- See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition) for more information on how this function works.
- See [Google](https://developer.chrome.com/docs/web-platform/view-transitions/same-document#view-transition-types) for more information on viewTransition types
+### `replayViewTransitionOnTraversal` property
+
+- Type: `boolean`
+- Optional, defaults to `false`
+- If `true`, replays the view transition a navigation opted into (`` / `navigate({ viewTransition })`) when the user later traverses that entry with the browser Back/Forward buttons. Without it, those per-navigation opt-ins are not replayed on traversal, so Back/Forward fall back to the router's normal behavior (`defaultViewTransition` if set, otherwise no transition). Replay is symmetric: a transition opted into on `A → B` plays on both `B → A` (back) and a later `A → B` (forward).
+- Recorded values are kept in-memory (lost on hard reload, degrading to no transition) so a functional [`ViewTransitionOptions`](./ViewTransitionOptionsType.md) `types` callback survives. Opt-in; does not change `defaultViewTransition` behavior.
+
### `defaultHashScrollIntoView` property
- Type: `boolean | ScrollIntoViewOptions`
diff --git a/examples/react/view-transitions/src/directionAwareTransition.ts b/examples/react/view-transitions/src/directionAwareTransition.ts
new file mode 100644
index 0000000000..d8ed67b71c
--- /dev/null
+++ b/examples/react/view-transitions/src/directionAwareTransition.ts
@@ -0,0 +1,43 @@
+import type { ViewTransitionOptions } from '@tanstack/react-router'
+
+/**
+ * A direction-aware view transition based on PAGE ORDER, not history position.
+ *
+ * `__TSR_index` only tracks the history stack, so a "Previous Page" link (a
+ * forward PUSH) increments it even though you're moving to an earlier page.
+ * Instead we rank pages by their place in the app's sequence and slide toward
+ * the later page — so the same logical move always animates the same way,
+ * whether reached by a link or by browser Back/Forward.
+ *
+ * `types` is a FUNCTION, so it re-resolves against each navigation's from/to;
+ * `replayViewTransitionOnTraversal` keeps it live by reference so Back/Forward
+ * recompute the correct direction.
+ */
+const PAGE_ORDER = ['/', '/how-it-works', '/explore', '/posts']
+
+/** Rank a pathname within `PAGE_ORDER` using the longest matching prefix. */
+function pageRank(pathname: string): number {
+ // longest matching prefix so e.g. /posts/123 ranks with /posts
+ let best = -1
+ let bestLen = -1
+ PAGE_ORDER.forEach((p, i) => {
+ const matches = p === '/' ? pathname === '/' : pathname.startsWith(p)
+ if (matches && p.length > bestLen) {
+ best = i
+ bestLen = p.length
+ }
+ })
+ return best
+}
+
+export const slideByDirection: ViewTransitionOptions = {
+ types: ({ fromLocation, toLocation }) => {
+ if (!fromLocation) {
+ return ['slide-left']
+ }
+ const from = pageRank(fromLocation.pathname)
+ const to = pageRank(toLocation.pathname)
+ // Moving to a later page slides left; to an earlier page slides right.
+ return [to >= from ? 'slide-left' : 'slide-right']
+ },
+}
diff --git a/examples/react/view-transitions/src/main.tsx b/examples/react/view-transitions/src/main.tsx
index 065d69a2cf..d901de51b5 100644
--- a/examples/react/view-transitions/src/main.tsx
+++ b/examples/react/view-transitions/src/main.tsx
@@ -10,6 +10,8 @@ const router = createRouter({
defaultPreload: 'intent',
defaultStaleTime: 5000,
scrollRestoration: true,
+ // Replay each navigation's view transition on browser Back/Forward (PR #7697)
+ replayViewTransitionOnTraversal: true,
/*
Using defaultViewTransition would prevent the need to
manually add `viewTransition: true` to every navigation.
diff --git a/examples/react/view-transitions/src/routes/explore.tsx b/examples/react/view-transitions/src/routes/explore.tsx
index b70a6f3bd5..c1476dae2d 100644
--- a/examples/react/view-transitions/src/routes/explore.tsx
+++ b/examples/react/view-transitions/src/routes/explore.tsx
@@ -1,4 +1,5 @@
import { Link, createFileRoute } from '@tanstack/react-router'
+import { slideByDirection } from '../directionAwareTransition'
export const Route = createFileRoute('/explore')({
component: RouteComponent,
@@ -18,8 +19,8 @@ function RouteComponent() {