--- name: TanStack Router description: Expert guidance for TanStack Router including file-based routing, type-safe navigation, route loaders, search params, nested routes, and lazy loading. Use this when building type-safe React applications with client-side routing. --- # TanStack Router Expert assistance with TanStack Router - Type-safe routing for React. ## Overview TanStack Router is a fully type-safe React router: - **File-Based Routing**: Automatic route generation from file structure - **Type Safety**: Full TypeScript inference for params, search, and more - **Code Splitting**: Automatic route-based code splitting - **Data Loading**: Built-in data loaders - **Search Params**: Type-safe search parameter handling ## Installation ```bash npm install @tanstack/react-router npm install --save-dev @tanstack/router-vite-plugin ``` ## Basic Setup ### Vite Configuration ```typescript // vite.config.ts import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { TanStackRouterVite } from '@tanstack/router-vite-plugin'; export default defineConfig({ plugins: [ react(), TanStackRouterVite(), ], }); ``` ### Root Route ```typescript // src/routes/__root.tsx import { createRootRoute, Outlet } from '@tanstack/react-router'; export const Route = createRootRoute({ component: () => ( <>

), }); ``` ### Index Route ```typescript // src/routes/index.tsx import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/')({ component: () =>
Home Page
, }); ``` ## File-Based Routing ``` src/routes/ ├── __root.tsx -> / ├── index.tsx -> / ├── certificates/ │ ├── index.tsx -> /certificates │ └── $id.tsx -> /certificates/:id ├── cas/ │ ├── index.tsx -> /cas │ ├── $id.tsx -> /cas/:id │ └── $id.edit.tsx -> /cas/:id/edit └── audit.tsx -> /audit ``` ### Dynamic Routes ```typescript // src/routes/certificates/$id.tsx import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/certificates/$id')({ component: CertificateDetail, }); function CertificateDetail() { const { id } = Route.useParams(); // Type-safe! return
Certificate: {id}
; } ``` ### Nested Routes ```typescript // src/routes/certificates.tsx (layout) import { createFileRoute, Outlet } from '@tanstack/react-router'; export const Route = createFileRoute('/certificates')({ component: () => (

Certificates

{/* Render child routes */}
), }); // src/routes/certificates/index.tsx export const Route = createFileRoute('/certificates/')({ component: () =>
Certificate List
, }); // src/routes/certificates/$id.tsx export const Route = createFileRoute('/certificates/$id')({ component: () => { const { id } = Route.useParams(); return
Certificate {id}
; }, }); ``` ## Navigation ```typescript import { Link, useNavigate } from '@tanstack/react-router'; function MyComponent() { const navigate = useNavigate(); return ( <> {/* Link component */} Certificates {/* With params */} Certificate 123 {/* With search params */} Active Certificates {/* Programmatic navigation */} {/* Navigate with params */} ); } ``` ## Search Params ### Define Search Schema ```typescript import { createFileRoute } from '@tanstack/react-router'; import { z } from 'zod'; const searchSchema = z.object({ filter: z.enum(['all', 'active', 'revoked']).optional().default('all'), page: z.number().optional().default(1), pageSize: z.number().optional().default(10), }); export const Route = createFileRoute('/certificates/')({ validateSearch: searchSchema, component: CertificateList, }); function CertificateList() { const { filter, page, pageSize } = Route.useSearch(); // Type-safe! return (

Filter: {filter}, Page: {page}

); } ``` ### Update Search Params ```typescript import { useNavigate } from '@tanstack/react-router'; function FilterButtons() { const navigate = useNavigate({ from: '/certificates' }); const search = Route.useSearch(); return ( <> ); } ``` ## Route Loaders ```typescript import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/certificates/$id')({ loader: async ({ params }) => { const certificate = await fetchCertificate(params.id); return { certificate }; }, component: CertificateDetail, }); function CertificateDetail() { const { certificate } = Route.useLoaderData(); return
{certificate.subject}
; } ``` ### Loader with Context ```typescript // src/router.tsx import { createRouter } from '@tanstack/react-router'; const router = createRouter({ routeTree, context: { queryClient, // React Query client auth, // Auth context }, }); // Route with context export const Route = createFileRoute('/certificates/$id')({ loader: async ({ params, context }) => { const certificate = await context.queryClient.fetchQuery({ queryKey: ['certificate', params.id], queryFn: () => fetchCertificate(params.id), }); return { certificate }; }, }); ``` ## Lazy Loading ```typescript // src/routes/certificates/$id.lazy.tsx import { createLazyFileRoute } from '@tanstack/react-router'; export const Route = createLazyFileRoute('/certificates/$id')({ component: CertificateDetail, }); // Component defined in same file (lazy loaded) function CertificateDetail() { const { id } = Route.useParams(); return
Certificate: {id}
; } ``` ## Error Handling ```typescript export const Route = createFileRoute('/certificates/$id')({ loader: async ({ params }) => { const certificate = await fetchCertificate(params.id); if (!certificate) { throw new Error('Certificate not found'); } return { certificate }; }, errorComponent: ({ error }) => (

Error!

{error.message}

), component: CertificateDetail, }); ``` ## Pending/Loading States ```typescript export const Route = createFileRoute('/certificates/$id')({ loader: async ({ params }) => { const certificate = await fetchCertificate(params.id); return { certificate }; }, pendingComponent: () =>
Loading certificate...
, component: CertificateDetail, }); // Or use hook function CertificateDetail() { const { certificate } = Route.useLoaderData(); const isPending = Route.useLoaderPending(); if (isPending) return
Loading...
; return
{certificate.subject}
; } ``` ## Route Guards ```typescript export const Route = createFileRoute('/admin')({ beforeLoad: async ({ context }) => { if (!context.auth.isAuthenticated) { throw redirect({ to: '/login' }); } }, component: AdminPanel, }); ``` ## Router Setup ```typescript // src/router.tsx import { createRouter } from '@tanstack/react-router'; import { routeTree } from './routeTree.gen'; export const router = createRouter({ routeTree, defaultPreload: 'intent', // Preload on hover defaultPreloadStaleTime: 0, }); declare module '@tanstack/react-router' { interface Register { router: typeof router; } } // src/main.tsx import { RouterProvider } from '@tanstack/react-router'; import { router } from './router'; function App() { return ; } ``` ## Best Practices 1. **File Structure**: Organize routes by feature/domain 2. **Type Safety**: Leverage full type inference 3. **Search Params**: Define schemas for search params 4. **Code Splitting**: Use lazy routes for large components 5. **Error Boundaries**: Implement error components 6. **Loading States**: Show pending UI for better UX 7. **Preloading**: Use intent-based preloading 8. **Route Guards**: Protect routes with beforeLoad 9. **Loaders**: Fetch data in loaders, not components 10. **Context**: Share context through router ## Resources - Documentation: https://tanstack.com/router - GitHub: https://github.com/TanStack/router