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:
<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.
Recommended Solutions
Solution 1: Using matchRoutes
with Defined Routes
The most reliable approach is to use React Router's matchRoutes
function with your route configuration:
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):
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:
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:
// 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 /> },
]
}
]
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
}
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:
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
Solution | Best For | Limitations |
---|---|---|
matchRoutes | Most applications, nested routes | Requires access to route config |
UNSAFE_RouteContext | When route config unavailable | Unstable API, may break updates |
Parameter replacement | Simple, flat routes | Fails with nested/complex routes |
Predefined patterns | Limited, known route set | Manual 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.