Skip to main content
TanStack Router provides a comprehensive set of hooks for accessing router state, navigation, and route information with full type safety.

Router Hooks

useRouter

Access the current TanStack Router instance from React context.
import { useRouter } from '@tanstack/react-router'

function MyComponent() {
  const router = useRouter()
  
  return <div>Current path: {router.state.location.pathname}</div>
}
Source: packages/react-router/src/useRouter.tsx:16-25
opts
{ warn?: boolean }
returns
TRouter
The registered router instance.

useRouterState

Subscribe to the router’s state store with optional selection and structural sharing.
import { useRouterState } from '@tanstack/react-router'

function MyComponent() {
  const isLoading = useRouterState({ 
    select: (state) => state.isLoading 
  })
  
  return isLoading ? <Spinner /> : <Content />
}
Source: packages/react-router/src/useRouterState.tsx:44-86
opts
UseRouterStateOptions
returns
TSelected | RouterState
The selected router state (or the full state by default).

useNavigate

Imperative navigation hook that returns a stable navigate function.
import { useNavigate } from '@tanstack/react-router'

function MyComponent() {
  const navigate = useNavigate()
  
  const handleClick = () => {
    navigate({ to: '/posts/$postId', params: { postId: '123' } })
  }
  
  return <button onClick={handleClick}>Go to Post</button>
}
Source: packages/react-router/src/useNavigate.tsx:26-43
defaultOpts
{ from?: string }
returns
(options: NavigateOptions) => Promise<void>
A function that accepts NavigateOptions including:
  • to - Destination path
  • params - Path parameters
  • search - Search parameters
  • hash - URL hash
  • replace - Replace history entry
  • resetScroll - Reset scroll position

useLocation

Read the current location from the router state.
import { useLocation } from '@tanstack/react-router'

function MyComponent() {
  const location = useLocation()
  
  return <div>Current path: {location.pathname}</div>
}
Source: packages/react-router/src/useLocation.tsx:40-52
opts
UseLocationOptions
returns
Location | TSelected
The current location object with properties:
  • pathname - Current path
  • search - Parsed search params
  • hash - URL hash
  • href - Full URL
  • state - Location state

Route Data Hooks

useParams

Access the current route’s path parameters with type safety.
import { useParams } from '@tanstack/react-router'

function PostComponent() {
  const { postId } = useParams({ from: '/posts/$postId' })
  
  return <div>Post ID: {postId}</div>
}
Source: packages/react-router/src/useParams.tsx:76-107
opts
UseParamsOptions
required
returns
TParams | TSelected
The params object (or selected value) for the matched route.

useSearch

Read and select the current route’s search parameters with type safety.
import { useSearch } from '@tanstack/react-router'

function PostsComponent() {
  const search = useSearch({ from: '/posts' })
  
  return <div>Page: {search.page}</div>
}
Source: packages/react-router/src/useSearch.tsx:76-105
opts
UseSearchOptions
required
returns
TSearch | TSelected
The search object (or selected value) for the matched route.

useLoaderData

Read and select the current route’s loader data with type safety.
import { useLoaderData } from '@tanstack/react-router'

function PostComponent() {
  const { post } = useLoaderData({ from: '/posts/$postId' })
  
  return <h1>{post.title}</h1>
}
Source: packages/react-router/src/useLoaderData.tsx:68-91
opts
UseLoaderDataOptions
required
returns
TLoaderData | TSelected
The loader data (or selected value) for the matched route.

Match Hooks

useMatch

Read and select the nearest or targeted route match.
import { useMatch } from '@tanstack/react-router'

function MyComponent() {
  const match = useMatch({ from: '/posts/$postId' })
  
  return <div>Match ID: {match.id}</div>
}
Source: packages/react-router/src/useMatch.tsx:82-123
opts
UseMatchOptions
required
returns
RouteMatch | TSelected
The route match object containing:
  • id - Match ID
  • routeId - Route ID
  • pathname - Matched pathname
  • params - Path parameters
  • search - Search parameters
  • loaderData - Loader data
  • context - Route context

useMatches

Read the full array of active route matches or select a derived subset.
import { useMatches } from '@tanstack/react-router'

function Breadcrumbs() {
  const matches = useMatches()
  
  return (
    <nav>
      {matches.map(match => (
        <span key={match.id}>{match.routeId}</span>
      ))}
    </nav>
  )
}
Source: packages/react-router/src/Matches.tsx:233-250
opts
UseMatchesOptions
returns
RouteMatch[] | TSelected
The array of matches (or the selected value).

useMatchRoute

Create a matcher function for testing locations against route definitions.
import { useMatchRoute } from '@tanstack/react-router'

function MyComponent() {
  const matchRoute = useMatchRoute()
  const isPostsPage = matchRoute({ to: '/posts' })
  
  return isPostsPage ? <PostsHeader /> : <DefaultHeader />
}
Source: packages/react-router/src/Matches.tsx:144-174
returns
(options: MatchRouteOptions) => false | TParams
A matchRoute function that returns false (no match) or the matched params object. Options include:
  • to - Route to match
  • params - Match specific params
  • search - Match specific search
  • fuzzy - Allow fuzzy matching
  • pending - Match against pending location
  • caseSensitive - Case-sensitive matching

Blocker Hook

useBlocker

Block navigation with custom logic and optional user confirmation.
import { useBlocker } from '@tanstack/react-router'

function FormComponent() {
  const [isDirty, setIsDirty] = useState(false)
  
  useBlocker({
    shouldBlockFn: () => isDirty,
    enableBeforeUnload: true,
    withResolver: true,
  })
  
  return <form>...</form>
}
Source: packages/react-router/src/useBlocker.tsx:131-260
opts
UseBlockerOpts
required
returns
void | BlockerResolver
When withResolver: true, returns:
  • status - ‘idle’ | ‘blocked’
  • current - Current location info
  • next - Next location info
  • action - History action
  • proceed() - Allow navigation
  • reset() - Cancel navigation

Usage Examples

Router State Selection

function NavigationIndicator() {
  const { isLoading, location } = useRouterState({
    select: (state) => ({
      isLoading: state.isLoading,
      location: state.location.pathname,
    }),
  })
  
  return isLoading ? <ProgressBar /> : null
}

Imperative Navigation

function LoginButton() {
  const navigate = useNavigate()
  
  const handleLogin = async () => {
    await loginUser()
    navigate({ 
      to: '/dashboard',
      replace: true,
    })
  }
  
  return <button onClick={handleLogin}>Login</button>
}

Type-Safe Params

function PostPage() {
  const { postId, commentId } = useParams({ 
    from: '/posts/$postId/comments/$commentId',
    select: (params) => ({
      postId: params.postId,
      commentId: params.commentId,
    }),
  })
  
  return <Comment postId={postId} commentId={commentId} />
}

Search Params with Selection

function ProductList() {
  const page = useSearch({
    from: '/products',
    select: (search) => search.page ?? 1,
  })
  
  const products = useProducts(page)
  
  return <ProductGrid products={products} />
}

Loader Data Access

function UserProfile() {
  const user = useLoaderData({
    from: '/users/$userId',
    select: (data) => data.user,
  })
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  )
}

Conditional Rendering with Match

function Navigation() {
  const matchRoute = useMatchRoute()
  
  const isSettings = matchRoute({ to: '/settings', fuzzy: true })
  const isAdmin = matchRoute({ to: '/admin' })
  
  return (
    <nav>
      <Link to="/">Home</Link>
      {isSettings && <SettingsNav />}
      {isAdmin && <AdminNav />}
    </nav>
  )
}
function Breadcrumbs() {
  const matches = useMatches({
    select: (matches) => matches.map(match => ({
      id: match.id,
      pathname: match.pathname,
      // Access custom metadata from route
      title: match.context?.breadcrumb,
    })),
  })
  
  return (
    <nav>
      {matches.map((match, i) => (
        <span key={match.id}>
          {i > 0 && ' > '}
          <Link to={match.pathname}>{match.title}</Link>
        </span>
      ))}
    </nav>
  )
}
function EditForm() {
  const [formData, setFormData] = useState(initialData)
  const [originalData] = useState(initialData)
  
  const hasChanges = !deepEqual(formData, originalData)
  
  const blocker = useBlocker({
    shouldBlockFn: ({ current, next }) => {
      return hasChanges && current.routeId !== next.routeId
    },
    withResolver: true,
  })
  
  return (
    <>
      <form>
        <input 
          value={formData.title}
          onChange={(e) => setFormData({ ...formData, title: e.target.value })}
        />
      </form>
      
      {blocker.status === 'blocked' && (
        <Dialog>
          <p>You have unsaved changes. Are you sure you want to leave?</p>
          <button onClick={blocker.proceed}>Leave</button>
          <button onClick={blocker.reset}>Stay</button>
        </Dialog>
      )}
    </>
  )
}

Location Tracking

function Analytics() {
  const pathname = useLocation({ 
    select: (loc) => loc.pathname 
  })
  
  useEffect(() => {
    trackPageView(pathname)
  }, [pathname])
  
  return null
}

Performance Tips

Use Selectors

Always use the select option to narrow down your subscription:
// ❌ Re-renders on any router state change
const state = useRouterState()

// ✅ Only re-renders when isLoading changes
const isLoading = useRouterState({ 
  select: (s) => s.isLoading 
})

Enable Structural Sharing

For complex selections, enable structural sharing:
const metadata = useMatches({
  select: (matches) => matches.map(m => m.context?.metadata),
  structuralSharing: true, // Prevents unnecessary re-renders
})

Memoize Selectors

For expensive selections, memoize the selector:
const selector = useCallback(
  (state) => computeExpensiveValue(state),
  [dependencies]
)

const value = useRouterState({ select: selector })

See Also

Build docs developers (and LLMs) love