
navigation
Link component, useNavigate, Navigate component, router.navigate, ToOptions/NavigateOptions/LinkOptions, from/to relative navigation, activeOptions/activeProps, preloading (intent/viewport/render), preloadDelay, navigation blocking (useBlocker, Block), createLink, linkOptions helper, scroll restoration, MatchRoute.
- Installs
- 198
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/tanstack/router --skill navigation- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads navigation automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Navigation
Setup
Basic type-safe Link with to and params:
import { Link } from '@tanstack/react-router'
function PostLink({ postId }: { postId: string }) {
return (
<Link to="/posts/$postId" params={{ postId }}>
View Post
</Link>
)
}
Core Patterns
Link with Active States
import { Link } from '@tanstack/react-router'
function NavLink() {
return (
<Link
to="/posts"
activeProps={{ className: 'font-bold' }}
inactiveProps={{ className: 'text-gray-500' }}
activeOptions={{ exact: true }}
>
Posts
</Link>
)
}
The data-status attribute is also set to "active" on active links for CSS-based styling.
activeOptions controls matching behavior:
exact(defaultfalse) — whentrue, only matches the exact path (not children)includeHash(defaultfalse) — include hash in active matchingincludeSearch(defaulttrue) — include search params in active matching
Children can receive isActive as a render function:
<Link to="/posts">
{({ isActive }) => <span className={isActive ? 'font-bold' : ''}>Posts</span>}
</Link>
Relative Navigation with from
Without from, navigation resolves from root /. To use relative paths like .., provide from:
import { createFileRoute, Link } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
})
function PostComponent() {
return (
<div>
{/* Relative to current route */}
<Link from={Route.fullPath} to="..">
Back to Posts
</Link>
{/* "." reloads the current route */}
<Link from={Route.fullPath} to=".">
Reload
</Link>
</div>
)
}
useNavigate for Programmatic Navigation
Use useNavigate only for side-effect-driven navigation (e.g., after a form submission). For anything the user clicks, prefer Link.
import { useNavigate } from '@tanstack/react-router'
function CreatePostForm() {
const navigate = useNavigate({ from: '/posts' })
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
const response = await fetch('/api/posts', { method: 'POST', body: '...' })
const { id: postId } = await response.json()
if (response.ok) {
navigate({ to: '/posts/$postId', params: { postId } })
}
}
return <form onSubmit={handleSubmit}>{/* ... */}</form>
}
The Navigate component performs an immediate client-side navigation on mount:
import { Navigate } from '@tanstack/react-router'
function LegacyRedirect() {
return <Navigate to="/posts/$postId" params={{ postId: 'my-first-post' }} />
}
router.navigate is available anywhere you have the router instance, including outside of React.
Preloading
Strategies: intent (hover/touchstart), viewport (intersection observer), render (on mount).
Set globally:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
routeTree,
defaultPreload: 'intent',
defaultPreloadDelay: 50, // ms, default is 50
})
Or per-link:
<Link
to="/posts/$postId"
params={{ postId }}
preload="intent"
preloadDelay={100}
>
View Post
</Link>
Preloaded data stays fresh for 30 seconds by default (defaultPreloadStaleTime: 30_000). During that window it won't be refetched. When using an external cache like TanStack Query, set defaultPreloadStaleTime: 0 to let the external library control freshness.
Manual preloading via the router instance:
import { useRouter } from '@tanstack/react-router'
function Component() {
const router = useRouter()
useEffect(() => {
router.preloadRoute({ to: '/posts/$postId', params: { postId: '1' } })
}, [router])
return <div />
}
Navigation Blocking
Use useBlocker to prevent navigation when a form has unsaved changes:
import { useBlocker } from '@tanstack/react-router'
import { useState } from 'react'
function EditForm() {
const [formIsDirty, setFormIsDirty] = useState(false)
useBlocker({
shouldBlockFn: () => {
if (!formIsDirty) return false
const shouldLeave = confirm('Are you sure you want to leave?')
return !shouldLeave
},
})
return <form>{/* ... */}</form>
}
With custom UI using withResolver:
import { useBlocker } from '@tanstack/react-router'
import { useState } from 'react'
function EditForm() {
const [formIsDirty, setFormIsDirty] = useState(false)
const { proceed, reset, status } = useBlocker({
shouldBlockFn: () => formIsDirty,
withResolver: true,
})
return (
<>
<form>{/* ... */}</form>
{status === 'blocked' && (
<div>
<p>Are you sure you want to leave?</p>
<button onClick={proceed}>Yes</button>
<button onClick={reset}>No</button>
</div>
)}
</>
)
}
Control beforeunload separately:
useBlocker({
shouldBlockFn: () => formIsDirty,
enableBeforeUnload: formIsDirty,
})
linkOptions for Reusable Navigation Options
linkOptions provides eager type-checking on navigation options objects, so errors surface at definition, not at spread-site:
import {
linkOptions,
Link,
useNavigate,
redirect,
} from '@tanstack/react-router'
const dashboardLinkOptions = linkOptions({
to: '/dashboard',
search: { search: '' },
})
// Use anywhere: Link, navigate, redirect
function Nav() {
const navigate = useNavigate()
return (
<div>
<Link {...dashboardLinkOptions}>Dashboard</Link>
<button onClick={() => navigate(dashboardLinkOptions)}>Go</button>
</div>
)
}
// Also works in an array for navigation bars
const navOptions = linkOptions([
{ to: '/dashboard', label: 'Summary', activeOptions: { exact: true } },
{ to: '/dashboard/invoices', label: 'Invoices' },
{ to: '/dashboard/users', label: 'Users' },
])
function NavBar() {
return (
<nav>
{navOptions.map((option) => (
<Link
{...option}
key={option.to}
activeProps={{ className: 'font-bold' }}
>
{option.label}
</Link>
))}
</nav>
)
}
createLink for Custom Components
Wraps any component with TanStack Router's type-safe navigation:
import * as React from 'react'
import { createLink, LinkComponent } from '@tanstack/react-router'
interface BasicLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {}
const BasicLinkComponent = React.forwardRef<HTMLAnchorElement, BasicLinkProps>(
(props, ref) => {
return <a ref={ref} {...props} className="block px-3 py-2 text-blue-700" />
},
)
const CreatedLinkComponent = createLink(BasicLinkComponent)
export const CustomLink: LinkComponent<typeof BasicLinkComponent> = (props) => {
return <CreatedLinkComponent preload="intent" {...props} />
}
Usage retains full type safety:
<CustomLink to="/dashboard/invoices/$invoiceId" params={{ invoiceId: 0 }} />
Scroll Restoration
Enable globally on the router:
const router = createRouter({
routeTree,
scrollRestoration: true,
})
For nested scrollable areas:
const router = createRouter({
routeTree,
scrollRestoration: true,
scrollToTopSelectors: ['#main-scrollable-area'],
})
Custom cache keys:
const router = createRouter({
routeTree,
scrollRestoration: true,
getScrollRestorationKey: (location) => location.pathname,
})
Prevent scroll reset for a specific navigation:
<Link to="/posts" resetScroll={false}>
Posts
</Link>
MatchRoute for Pending UI
import { Link, MatchRoute } from '@tanstack/react-router'
function Nav() {
return (
<Link to="/users">
Users
<MatchRoute to="/users" pending>
<Spinner />
</MatchRoute>
</Link>
)
}
Common Mistakes
CRITICAL: Interpolating params into the to string
// WRONG — breaks type safety and param encoding
<Link to={`/posts/${postId}`}>Post</Link>
// CORRECT — use the params option
<Link to="/posts/$postId" params={{ postId }}>Post</Link>
Dynamic segments are declared with $ in the route path. Always pass them via params. This applies to Link, useNavigate, Navigate, and router.navigate.
MEDIUM: Using useNavigate for clickable elements
// WRONG — no href, no cmd+click, no preloading, no accessibility
function BadNav() {
const navigate = useNavigate()
return <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
}
// CORRECT — real <a> tag with href, accessible, preloadable
function GoodNav() {
return <Link to="/posts">Posts</Link>
}
Use useNavigate only for programmatic side-effect navigation (after form submit, async action, etc).
HIGH: Not providing from for relative navigation
// WRONG — without from, ".." resolves from root
<Link to="..">Back</Link>
// CORRECT — provide from for relative resolution
<Link from={Route.fullPath} to="..">Back</Link>
Without from, only absolute paths are autocompleted and type-safe. Relative paths like .. resolve from root instead of the current route.
HIGH: Using search as object instead of function loses existing params
// WRONG — replaces ALL search params with just { page: 2 }
<Link to="." search={{ page: 2 }}>Page 2</Link>
// CORRECT — preserves existing search params, updates page
<Link to="." search={(prev) => ({ ...prev, page: 2 })}>Page 2</Link>
When you pass search as a plain object, it replaces all search params. Use the function form to spread previous params and selectively update.
Cross-References
- See also: router-core/search-params/SKILL.md — Link
searchprop interacts with search param validation - See also: router-core/type-safety/SKILL.md —
fromnarrowing improves type inference on Link
FAQ
What does the navigation skill do?
Link component, useNavigate, Navigate component, router.navigate, ToOptions/NavigateOptions/LinkOptions, from/to relative navigation, activeOptions/activeProps, preloading (intent/viewport/render), preloadDelay, navigation blocking (useBlocker, Block), createLink, linkOptions helper, scroll restoration, MatchRoute.
How do I install navigation?
Run npx skills add https://github.com/tanstack/router --skill navigation in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/navigation/ (personal) or .claude/skills/navigation/ (project).
Which AI agents can use navigation?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is navigation safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains navigation?
It is published by tanstack in tanstack/router. It has 198 recorded installs.
More from tanstack/router
router-core
tanstack/router
Framework-agnostic core concepts for TanStack Router: route trees, createRouter, createRoute, createRootRoute, createRootRouteWithContext, addChildren, Register type declaration, route matching, route sorting, file naming conventions. Entry point for all router skills.
react-router
tanstack/router
React bindings for TanStack Router: RouterProvider, useRouter, useRouterState, useMatch, useMatches, useLocation, useSearch, useParams, useNavigate, useLoaderData, useLoaderDeps, useRouteContext, useBlocker, useCanGoBack, Link, Navigate, Outlet, CatchBoundary, ErrorComponent. React-specific patterns for hooks, providers, SSR hydration, and createLink with forwardRef.
react-start
tanstack/router
React bindings for TanStack Start: createStart, StartClient, StartServer, React-specific imports, re-exports from @tanstack/react-router, full project setup with React, useServerFn hook.
start-core
tanstack/router
Core overview for TanStack Start: tanstackStart() Vite plugin, getRouter() factory, root route document shell (HeadContent, Scripts, Outlet), client/server entry points, routeTree.gen.ts, tsconfig configuration. Entry point for all Start skills.
router-query
tanstack/router
Integrating TanStack Router with TanStack Query: queryClient in router context, static queries and fire-and-forget queries in loaders, useSuspenseQuery in components, defaultPreloadStaleTime: 0, setupRouterSsrQueryIntegration for SSR dehydration/hydration and streaming, per-request QueryClient isolation.
start-server-core
tanstack/router
Server-side runtime for TanStack Start: createStartHandler, request/response utilities (getRequest, setResponseHeader, setCookie, getCookie, appendResponseHeader), three-phase request handling, AsyncLocalStorage context.
Popular frontend & design skills
setup-matt-pocock-skills
mattpocock/skills
Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.
frontend-design
anthropics/skills
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
hyperframes-animation
heygen-com/hyperframes
All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.
prototype
mattpocock/skills
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.
hyperframes-core
heygen-com/hyperframes
The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.
vercel-react-best-practices
vercel-labs/agent-skills
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.