Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tanstack/router/llms.txt
Use this file to discover all available pages before exploring further.
Scroll restoration automatically manages scroll position when users navigate between routes, maintaining a smooth browsing experience.
TanStack Router automatically scrolls to top on navigation by default:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
routeTree,
// Default scroll behavior (scroll to top)
defaultScrollRestoration: 'top',
})
Configure global scroll behavior:
const router = createRouter({
routeTree,
defaultScrollRestoration: 'auto', // Browser default
// Or:
// 'top' - Always scroll to top
// false - Don't restore scroll
})
Override scroll behavior for specific routes:
export const Route = createFileRoute('/posts/$postId')({
component: Post,
// Don't scroll on this route
scrollRestoration: false,
})
Implement custom scroll logic:
import { ScrollRestoration } from '@tanstack/react-router'
function RootComponent() {
return (
<>
<Outlet />
<ScrollRestoration
getKey={(location) => {
// Restore scroll per path
return location.pathname
// Or per path + search params
// return location.pathname + location.search
}}
/>
</>
)
}
Automatically scroll to hash fragments:
import { Link } from '@tanstack/react-router'
function TableOfContents() {
return (
<nav>
<Link to="/docs" hash="#introduction">
Introduction
</Link>
<Link to="/docs" hash="#getting-started">
Getting Started
</Link>
</nav>
)
}
Control scroll position during navigation:
import { useNavigate } from '@tanstack/react-router'
function JumpToSection() {
const navigate = useNavigate()
const goToSection = () => {
navigate({
to: '/docs',
hash: '#advanced',
// Control scroll behavior
replace: false,
})
}
return <button onClick={goToSection}>Jump to Advanced</button>
}
Keep scroll position when navigating:
import { Link } from '@tanstack/react-router'
function Pagination() {
return (
<div>
<Link
to="/posts"
search={{ page: 2 }}
// Prevent scroll to top
resetScroll={false}
>
Next Page
</Link>
</div>
)
}
Use smooth scroll behavior:
html {
scroll-behavior: smooth;
}
Or control via JavaScript:
function smoothScrollTo(element: HTMLElement) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}
Scroll when route params change:
function PostComponent() {
const { postId } = Route.useParams()
const scrollRef = React.useRef<HTMLDivElement>(null)
React.useEffect(() => {
// Scroll to top when post changes
scrollRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
})
}, [postId])
return (
<div ref={scrollRef} className="scrollable">
<Post postId={postId} />
</div>
)
}
Track scroll position for analytics:
import { useRouterState } from '@tanstack/react-router'
function useScrollTracking() {
const location = useRouterState({ select: (s) => s.location })
React.useEffect(() => {
const handleScroll = () => {
const scrollPercentage =
(window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
// Track scroll depth
if (scrollPercentage > 75) {
analytics.track('Scrolled 75%', {
path: location.pathname,
})
}
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [location.pathname])
}
Handle scroll in nested layouts:
function DashboardLayout() {
const scrollRef = React.useRef<HTMLDivElement>(null)
const location = useRouterState({ select: (s) => s.location })
React.useEffect(() => {
// Scroll layout container to top on route change
scrollRef.current?.scrollTo({ top: 0 })
}, [location.pathname])
return (
<div>
<Sidebar />
<main ref={scrollRef} className="scrollable-content">
<Outlet />
</main>
</div>
)
}
Skip to content
Implement accessibility skip links:
function RootLayout() {
return (
<>
<a href="#main-content" className="skip-link">
Skip to main content
</a>
<Header />
<main id="main-content" tabIndex={-1}>
<Outlet />
</main>
</>
)
}
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
Implement infinite scroll with scroll restoration:
function PostsList() {
const { page = 1 } = Route.useSearch()
const navigate = useNavigate()
const posts = Route.useLoaderData()
const loadMore = () => {
navigate({
search: { page: page + 1 },
resetScroll: false, // Keep scroll position
})
}
React.useEffect(() => {
const handleScroll = () => {
const bottom =
window.innerHeight + window.scrollY >= document.body.scrollHeight - 100
if (bottom) loadMore()
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [page])
return (
<div>
{posts.map((post) => (
<PostCard key={post.id} post={post} />
))}
</div>
)
}
Best practices
Use hash links for same-page navigation
Hash links provide native browser scroll behavior and work without JavaScript.
Preserve scroll for pagination
Restore scroll on back button
Let the browser handle scroll restoration for back/forward navigation.
Scroll behavior can differ significantly on mobile - always test there.
Common patterns
function ScrollToTop() {
const [show, setShow] = React.useState(false)
React.useEffect(() => {
const handleScroll = () => {
setShow(window.scrollY > 300)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
if (!show) return null
return (
<button onClick={scrollToTop} className="scroll-to-top">
↑ Back to Top
</button>
)
}
const scrollPositions = new Map<string, number>()
function useScrollMemory(key: string) {
const ref = React.useRef<HTMLDivElement>(null)
// Restore scroll position
React.useEffect(() => {
const savedPosition = scrollPositions.get(key)
if (savedPosition && ref.current) {
ref.current.scrollTop = savedPosition
}
}, [key])
// Save scroll position on unmount
React.useEffect(() => {
return () => {
if (ref.current) {
scrollPositions.set(key, ref.current.scrollTop)
}
}
}, [key])
return ref
}
Next steps
Navigation
Learn navigation patterns
Link component
Explore Link API