Skip to content

React Router v6: Get Path Pattern for Current Route

When building applications with React Router v6, developers often need to access the path pattern that matched the current route (e.g., ":state/:city*") rather than just the actual URL values. This article explores the best solutions for retrieving the current route's path pattern.

Problem Statement

In React Router v6, components rendered by <Route> elements need access to the path pattern that defined their route, not just the actual parameter values. For example:

jsx
<Route
    path=":state/:city*"
    element={<Page />}
/>

Inside the Page component, you might want to know that the matching pattern was ":state/:city*" rather than just having access to the actual state and city values.

Solution 1: Using matchRoutes with Defined Routes

The most reliable approach is to use React Router's matchRoutes function with your route configuration:

jsx
import { matchRoutes, useLocation } from "react-router-dom"

// Define your routes (can be extracted to a separate file)
const appRoutes = [
  { path: ':state/:city*' },
  // other routes...
]

function useCurrentPathPattern() {
  const location = useLocation()
  const matches = matchRoutes(appRoutes, location)
  
  if (!matches) return null
  
  return matches
    .map(({ route }) => route.path)
    .filter(Boolean)
    .join('/')
}

// Usage in component
function Page() {
  const pathPattern = useCurrentPathPattern() // Returns ":state/:city*"
  // ...
}

TIP

This approach works well for nested routes too, as it collects path patterns from all matching route segments.

Solution 2: Using UNSAFE_RouteContext (Advanced)

If you don't have access to your route configuration, you can use the internal RouteContext (note the "UNSAFE" prefix indicates this may change in future versions):

jsx
import { UNSAFE_RouteContext } from 'react-router-dom'
import { useContext, useMemo } from 'react'

function useRoutePattern() {
  const routeContext = useContext(UNSAFE_RouteContext)
  
  return useMemo(
    () =>
      routeContext.matches
        .map(({ route: { path } }) => path)
        .filter(Boolean)
        .join('/')
        .replaceAll(/\/\*?\//g, '/'),
    [routeContext.matches],
  )
}

WARNING

The UNSAFE_RouteContext approach uses React Router's internal API, which may change without notice in future versions. Use this only if you understand the risks and need a solution without access to route configuration.

Solution 3: Parameter Replacement Approach

For simple cases without nested routes, you can transform the actual URL back to the pattern:

jsx
import { useLocation, useParams } from "react-router-dom"

function usePathPattern() {
  const { pathname } = useLocation()
  const params = useParams()
  
  return Object.entries(params).reduce((path, [key, value]) => {
    return path.replace(`/${value}`, `/:${key}`)
  }, pathname)
}

DANGER

This solution has limitations with nested routes and complex path patterns. It may not work correctly if parameter values contain slashes or special characters.

Complete Example with Route Configuration

Here's a complete implementation using the recommended approach:

js
// Centralized route configuration
export const appRoutes = [
  { 
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <Home /> },
      { path: 'about', element: <About /> },
      { 
        path: 'users',
        element: <UsersLayout />,
        children: [
          { index: true, element: <UsersIndex /> },
          { path: ':userId', element: <UserProfile /> },
          { path: ':userId/posts', element: <UserPosts /> },
        ]
      },
      { path: ':state/:city*', element: <LocationPage /> },
    ]
  }
]
jsx
import { matchRoutes, useLocation } from "react-router-dom"
import { appRoutes } from './routes'

export function usePathPattern() {
  const location = useLocation()
  const matches = matchRoutes(appRoutes, location)
  
  if (!matches) return null
  
  return matches
    .map(({ route }) => route.path)
    .filter(Boolean)
    .join('/')
    .replaceAll(/\/\*$/, '/*') // Handle wildcard endings
}
jsx
import { usePathPattern } from './usePathPattern'

function LocationPage() {
  const pathPattern = usePathPattern() // Returns ":state/:city*" or ":state/:city/*"
  const params = useParams()
  
  return (
    <div>
      <h2>Current path pattern: {pathPattern}</h2>
      <p>State: {params.state}</p>
      <p>City: {params.city}</p>
    </div>
  )
}

Alternative Approach: Predefined Route Patterns

If you only need to check against specific patterns, you can use this simpler approach:

jsx
import { matchPath, useLocation } from "react-router-dom"

const routePatterns = [
  "/",
  "/about",
  "/users",
  "/users/:userId",
  "/:state/:city*"
]

function useMatchPathPattern() {
  const { pathname } = useLocation()
  return routePatterns.find(pattern => matchPath(pattern, pathname))
}

When to Use Each Solution

SolutionBest ForLimitations
matchRoutesMost applications, nested routesRequires access to route config
UNSAFE_RouteContextWhen route config unavailableUnstable API, may break updates
Parameter replacementSimple, flat routesFails with nested/complex routes
Predefined patternsLimited, known route setManual maintenance needed

Conclusion

For most React Router v6 applications, the matchRoutes approach provides the most reliable way to access the current route's path pattern. By centralizing your route configuration and using this utility function, you can consistently retrieve the pattern that matched the current URL across your application.

Remember that accessing route patterns should generally be reserved for advanced use cases—in most situations, working with actual parameter values (via useParams) is preferable and more maintainable.