React Router Cheatsheet
Routes and Nesting
Use this React Router reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Path Patterns
| Pattern | Matches | params |
|---|---|---|
/about | /about only | {} |
/users/:id | /users/42 | { id: "42" } |
/users/:id/posts/:postId | /users/1/posts/9 | { id: "1", postId: "9" } |
/files/* | /files/a/b/c.txt | { "*": "a/b/c.txt" } |
/:lang?/about | /about and /en/about | { lang: undefined | "en" } |
/ with index: true | The parent's exact path | {} |
* | Anything unmatched (404) | { "*": "…" } |
Params are always strings, or undefined for an optional segment that did not match. Convert them yourself: Number(params.id) and validate before using it.
<Route path="users/:id" element={<User />} /> <Route path="files/*" element={<Files />} /> <Route path=":lang?/settings" element={<Settings />} />
Ranking, Not Order
React Router scores routes by specificity and matches the best one, so the order you declare them in does not matter. This is the biggest behavioral difference from v5.
/users/new static segment wins /users/:id dynamic segment /users/* splat loses to both
So /users/new matches the static route even if the dynamic one is declared first. A single * route is always the last resort, which makes it the natural 404.
Nested Routes
Nesting composes both the URL and the UI. A child's path is appended to its parent's, and a child renders into its parent's <Outlet />.
const router = createBrowserRouter([ { path: "/dashboard", element: <DashboardLayout />, // renders at every /dashboard/* URL children: [ { index: true, element: <Overview /> }, // /dashboard { path: "settings", element: <Settings /> }, // /dashboard/settings { path: "projects", element: <ProjectsLayout />, // /dashboard/projects/* children: [ { index: true, element: <ProjectList /> }, // /dashboard/projects { path: ":id", element: <Project /> }, // /dashboard/projects/7 ], }, ], }, ]);
At /dashboard/projects/7 three components are mounted at once: DashboardLayout → ProjectsLayout → Project. The layouts keep their state across child navigations, which is what makes a persistent sidebar or an open form survive a URL change.
Index Routes
An index route is the child that renders when the URL is exactly the parent's path. Without one, the parent's <Outlet /> renders nothing.
{ path: "projects", element: <Layout />, children: [
{ index: true, element: <Empty /> }, // /projects
{ path: ":id", element: <Project /> }, // /projects/7
]}Layout Routes
A route with children and an element but no path wraps its children in shared UI without touching the URL.
[
{
element: <MarketingLayout />, // no path
children: [
{ path: "/", element: <Home /> },
{ path: "/pricing", element: <Pricing /> },
],
},
{
element: <AppLayout />, // different chrome
children: [
{ path: "/app", element: <App /> },
],
},
]Pathless and Absolute Paths
| Trick | Does |
|---|---|
No path on a parent | Shared layout, no URL segment |
Child path starting with / | Absolute, ignores the parent prefix |
Parent path with no element | Groups children under a URL prefix with no wrapper UI |
{
path: "/users",
children: [ // no element: URL grouping only
{ index: true, element: <UserList /> },
{ path: ":id", element: <User /> },
],
}Reading Params
import { useParams } from "react-router"; function Project() { const { id } = useParams(); // always a string const projectId = Number(id); if (!Number.isFinite(projectId)) throw new Response("Bad id", { status: 400 }); // … }
In framework mode, params are typed from the route path:
import type { Route } from "./+types/project"; export default function Project({ params }: Route.ComponentProps) { params.id; // typed as string, inferred from the file's route path }
Route Matching Utilities
import { matchPath, matchRoutes, useMatch, useMatches, generatePath, resolvePath, } from "react-router"; matchPath("/users/:id", "/users/42"); // { params: { id: "42" }, pathname: "/users/42", pattern: {…} } matchPath({ path: "/users/:id", end: false }, "/users/42/posts"); matchRoutes(routes, "/users/42"); // the full matched branch generatePath("/users/:id/posts/:postId", { id: 1, postId: 9 }); // "/users/1/posts/9" generatePath("/files/*", { "*": "a/b.txt" }); // "/files/a/b.txt"
function Nav() { const match = useMatch("/users/:id"); // null when it does not match const matches = useMatches(); // every matched route in the branch // matches[i]: { id, pathname, params, data, handle } }
useMatches plus a handle on each route is the standard way to build breadcrumbs, since it gives you the whole active branch with each route's own metadata.
{ path: "projects", element: <Projects />, handle: { crumb: () => "Projects" } }
function Breadcrumbs() {
const matches = useMatches();
const crumbs = matches
.filter((m) => Boolean(m.handle?.crumb))
.map((m) => m.handle.crumb(m.data));
return <ol>{crumbs.map((c, i) => <li key={i}>{c}</li>)}</ol>;
}Route Object Reference
| Property | Purpose |
|---|---|
path | The URL pattern |
index | This is the parent's index route |
element / Component | What to render |
lazy | Async import of the route's module |
children | Nested routes |
loader | Fetch data before render |
action | Handle a submission |
errorElement / ErrorBoundary | Catch errors from this subtree |
hydrateFallbackElement | Shown during SSR hydration with no data |
shouldRevalidate | Opt out of revalidation |
handle | Arbitrary metadata for useMatches |
caseSensitive | Match the path case-sensitively |
id | A stable id for useRouteLoaderData |
File-Based Routes (Framework Mode)
Framework mode's routes.ts is explicit by default, but a file-convention plugin is available.
import { type RouteConfig, index, route, layout, prefix } from "@react-router/dev/routes"; export default [ index("routes/home.tsx"), // / route("login", "routes/login.tsx"), // /login layout("routes/app-layout.tsx", [ ...prefix("app", [ index("routes/app-home.tsx"), // /app route(":id", "routes/app-detail.tsx"), // /app/:id route("*", "routes/app-404.tsx"), ]), ]), ] satisfies RouteConfig;
// or the flat file convention import { flatRoutes } from "@react-router/fs-routes"; export default flatRoutes();
| Helper | Adds |
|---|---|
index(file) | An index route |
route(path, file, children?) | A path route |
layout(file, children) | A pathless layout |
prefix(path, children) | A URL prefix with no layout |