Frontend & UISûr9292/100
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.
ou envoie-le directement à ton agent.
Installer dans ton projet
$ npx arboris-cli install react-router__tanstack-router__packages-react-router-skills-b72f526e5a17Contenu à copier
---
name: react-router
description: >-
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.
metadata:
origin: TanStack
type: framework
library: tanstack-router
library_version: '1.166.2'
framework: react
requires:
- router-core
sources:
- TanStack/router:packages/react-router/src
- TanStack/router:docs/router/guide/creating-a-router.md
- TanStack/router:docs/router/installation/manual.md
---
# React Router (`@tanstack/react-router`)
This skill builds on router-core. Read [router-core](../../../router-core/skills/router-core/SKILL.md) first for foundational concepts.
> **CRITICAL**: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, not on the server.
> **CRITICAL**: Do not confuse `@tanstack/react-router` with `react-router-dom`/`react-router`. They are completely different libraries with different APIs.
## Full Setup: File-Based Routing with Vite
### 1. Install Dependencies
```bash
npm install @tanstack/react-router
npm install -D @tanstack/router-plugin @tanstack/react-router-devtools
```
### 2. Configure Vite Plugin
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
// MUST come before react()
tanstackRouter({
target: 'react',
autoCodeSplitting: true,
}),
react(),
],
})
```
### 3. Create Root Route
```tsx
// src/routes/__root.tsx
import { createRootRoute, Link, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
export const Route = createRootRoute({
component: RootLayout,
})
function RootLayout() {
return (
<>
<nav>
<Link to="/" className="[&.active]:font-bold">
Home
</Link>
<Link to="/about" className="[&.active]:font-bold">
About
</Link>
</nav>
<hr />
<Outlet />
<TanStackRouterDevtools />
</>
)
}
```
### 4. Create Route Files
```tsx
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: HomePage,
})
function HomePage() {
return <h1>Welcome Home</h1>
}
```
```tsx
// src/routes/about.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/about')({
component: AboutPage,
})
function AboutPage() {
return <h1>About</h1>
}
```
### 5. Create Router Instance and Register Types
```tsx
// src/main.tsx
import { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider, createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
const router = createRouter({ routeTree })
// REQUIRED — without this, Link/useNavigate/useSearch have no type safety
declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}
const rootElement = document.getElementById('root')!
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement)
root.render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
)
}
```
## Hooks Reference
All hooks are imported from `@tanstack/react-router`.
### `useRouter()`
Access the router instance directly:
```tsx
import { useRouter } from '@tanstack/react-router'
function InvalidateButton() {
const router = useRouter()
return <button onClick={() => router.invalidate()}>Refresh data</button>
}
```
### `useRouterState()`
Subscribe to router state changes. Exposes the entire state and thus incurs
a performance cost. For matches or location favor `useMatches` and `useLocation`.
```tsx
import { useRouterState } from '@tanstack/react-router'
function LoadingIndicator() {
const isLoading = useRouterState({ select: (s) => s.isLoading })
return isLoading ? <div>Loading...</div> : null
}
```
### `useNavigate()`
Programmatic navigation (prefer `<Link>` for user-clickable elements):
```tsx
import { useNavigate } from '@tanstack/react-router'
function AfterSubmit() {
const navigate = useNavigate()
const handleSubmit = async () => {
await saveData()
navigate({ to: '/posts/$postId', params: { postId: '123' } })
}
return <button onClick={handleSubmit}>Save</button>
}
```
### `useSearch({ from })`
Read validated search params:
```tsx
import { useSearch } from '@tanstack/react-router'
function Pagination() {
const { page } = useSearch({ from: '/products' })
return <span>Page {page}</span>
}
```
### `useParams({ from })`
Read path params:
```tsx
import { useParams } from '@tanstack/react-router'
function PostHeader() {
const { postId } = useParams({ from: '/posts/$postId' })
return <h2>Post {postId}</h2>
}
```
### `useLoaderData({ from })`
Read data returned from the route loader:
```tsx
import { useLoaderData } from '@tanstack/react-router'
function PostContent() {
const { post } = useLoaderData({ from: '/posts/$postId' })
return <article>{post.content}</article>
}
```
### `useMatch({ from })`
Access the full route match (params, search, loader data, context):
```tsx
import { useMatch } from '@tanstack/react-router'
function PostDetails() {
const match = useMatch({ from: '/posts/$postId' })
return <div>{match.loaderData.post.title}</div>
}
```
### Other Hooks
All imported from `@tanstack/react-router`:
- **`useMatches()`** — array of all active route matches (useful for breadcrumbs)
- **`useRouteContext({ from })`** — read context from `beforeLoad` or parent routes
- **`useBlocker({ shouldBlockFn })`** — block navigation for unsaved changes
- **`useCanGoBack()`** — returns `boolean`, check if history has entries to go back to
- **`useLocation()`** — current parsed location (`pathname`, `search`, `hash`)
- **`useLinkProps({ to, params?, search? })`** — get `<a>` props for custom link elements
- **`useMatchRoute()`** — returns a function: `matchRoute({ to }) => match | false`
## Components Reference
### `RouterProvider`
Mount the router at the top of your React tree:
```tsx
<RouterProvider router={router} />
```
### `Link`
Type-safe navigation link with `<a>` semantics:
```tsx
<Link to="/posts/$postId" params={{ postId: '42' }}>
View Post
</Link>
```
### `Outlet`
Renders the matched child route component:
```tsx
function Layout() {
return (
<div>
<Sidebar />
<main>
<Outlet />
</main>
</div>
)
}
```
### `Navigate`
Declarative redirect component:
```tsx
import { Navigate } from '@tanstack/react-router'
function OldPage() {
return <Navigate to="/new-page" />
}
```
### `Await`
Renders deferred data from unawaited loader promises with Suspense:
```tsx
import { Await } from '@tanstack/react-router'
import { Suspense } from 'react'
function PostWithComments() {
const { deferredComments } = Route.useLoaderData()
return (
<div>
<h1>Post</h1>
<Suspense fallback={<div>Loading comments...</div>}>
<Await promise={deferredComments}>
{(comments) => (
<ul>
{comments.map((c) => (
<li key={c.id}>{c.text}</li>
))}
</ul>
)}
</Await>
</Suspense>
</div>
)
}
```
### `CatchBoundary`
Error boundary for component-level error handling (route-level errors use `errorComponent` route option):
```tsx
import { CatchBoundary } from '@tanstack/react-router'
;<CatchBoundary
getResetKey={() => 'widget'}
onCatch={(error) => console.error(error)}
errorComponent={({ error }) => <div>{String(error)}</div>}
>
<RiskyWidget />
</CatchBoundary>
```
## React-Specific Patterns
### Custom Link Component with `createLink`
Wrap `Link` in a custom component while preserving type safety:
```tsx
import { createLink } from '@tanstack/react-router'
import { forwardRef, type ComponentPropsWithoutRef } from 'react'
const StyledLinkComponent = forwardRef<
HTMLAnchorElement,
ComponentPropsWithoutRef<'a'>
>((props, ref) => (
<a ref={ref} {...props} className={`styled-link ${props.className ?? ''}`} />
))
const StyledLink = createLink(StyledLinkComponent)
// Usage — same type-safe props as Link
function Nav() {
return (
<StyledLink to="/posts/$postId" params={{ postId: '42' }}>
Post
</StyledLink>
)
}
```
### Reusable Components with Router Hooks
To create a component that uses router hooks across multiple routes, pass a union of route paths as the `from` prop:
```tsx
function PostIdDisplay({ from }: { from: '/posts/$id' | '/drafts/$id' }) {
const { id } = useParams({ from })
return <span>ID: {id}</span>
}
// Usage in different route components
<PostIdDisplay from="/posts/$id" />
<PostIdDisplay from="/drafts/$id" />
```
This pattern avoids `strict: false` (which returns an imprecise union) while keeping the component reusable across specific known routes.
### Auth Provider Must Wrap RouterProvider
If routes use auth context (via `createRootRouteWithContext`), the auth provider must be an ancestor of `RouterProvider`:
```tsx
// CORRECT — AuthProvider wraps RouterProvider
function App() {
return (
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
)
}
// WRONG — RouterProvider outside auth provider
function App() {
return (
<RouterProvider router={router}>
<AuthProvider>{/* ... */}</AuthProvider>
</RouterProvider>
)
}
```
Or use the `Wrap` router option to provide context without wrapping externally:
```tsx
const router = createRouter({
routeTree,
Wrap: ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
),
})
```
## Common Mistakes
### 1. HIGH: Using React hooks in `beforeLoad` or `loader`
`beforeLoad` and `loader` are NOT React components — they are plain async functions. React hooks cannot be called in them. Pass auth state via router context instead.
```tsx
// WRONG — useAuth is a React hook, cannot be called here
beforeLoad: () => {
const auth = useAuth()
if (!auth.user) throw redirect({ to: '/login' })
}
// CORRECT — read auth from router context
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login' })
}
}
```
### 2. HIGH: Wrapping RouterProvider inside an auth provider incorrectly
Create the router once with an `undefined!` placeholder, then inject live auth via `RouterProvider`'s `context` prop. Do NOT recreate the router on auth changes — this resets caches and rebuilds the tree.
```tsx
// CORRECT — create router once, inject live auth via context prop
const router = createRouter({
routeTree,
context: { auth: undefined! }, // placeholder, filled by RouterProvider
})
function InnerApp() {
const auth = useAuth()
return <RouterProvider router={router} context={{ auth }} />
}
function App() {
return (
<AuthProvider>
<InnerApp />
</AuthProvider>
)
}
```
### 3. MEDIUM: Missing Suspense boundary for `Await`/deferred data
`Await` requires a `<Suspense>` ancestor. Without it, the deferred promise has no fallback UI and throws.
```tsx
// WRONG — no Suspense boundary
<Await promise={deferredData}>{(data) => <div>{data}</div>}</Await>
// CORRECT — wrap in Suspense
<Suspense fallback={<div>Loading...</div>}>
<Await promise={deferredData}>{(data) => <div>{data}</div>}</Await>
</Suspense>
```
## Cross-References
- [router-core/SKILL.md](../../../router-core/skills/router-core/SKILL.md) — all sub-skills for domain-specific patterns (search params, data loading, navigation, auth, SSR, etc.)Colle ce Markdown dans ton agent ou utilise les boutons ci-dessus pour l’écrire dans ton projet.
Ce que fait react router tanstack router
**`useMatches()`** — array of all active route matches (useful for breadcrumbs)
**`useRouteContext({ from })`** — read context from `beforeLoad` or parent routes
**`useBlocker({ shouldBlockFn })`** — block navigation for unsaved changes
**`useCanGoBack()`** — returns `boolean`, check if history has entries to go back to
Comment utiliser react router tanstack router
1
Copie le prompt
Un clic copie le prompt packagé (ou l'envoie à ton agent).
2
L'agent installe le skill
Il ajoute le SKILL.md et ses ressources à ton projet.
3
Activation automatique
Le skill s'active dès que le contexte correspond.
Déclencheurs pour react router tanstack router
Dis simplement à ton agent quelque chose comme :
Applique le skill react-router__tanstack-router__packages-react-router-skills-b72f526e5a17 à cette tâche
Utilise react-router__tanstack-router__packages-react-router-skills-b72f526e5a17 pour améliorer cette implémentation
Passe en revue ce sujet avec react-router__tanstack-router__packages-react-router-skills-b72f526e5a17
Skills liés à react router tanstack router
accessibility
Design, implement, and audit inclusive digital products using WCAG 2.2 Level AAaccessibility pass microsoft cat agent skills
Use this skill whenever the user asks to check, review, or fix the accessibility of a PowerPoint deck, Word document, HTML page, or Markdown file, and before handing over any deck or document this agent just generated, so it does not ship with missing alt text, untitled slides, or unreadable colour contrast.add connector microsoft power platform skills
Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.