Skip to content

Commit d1c272a

Browse files
docs: add "using handle" how-to (#14405)
* docs: add route metadata guide * update breadcrumbs guide to be more focused on `handle` instead of "metadata"
1 parent 19ac8db commit d1c272a

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

docs/how-to/using-handle.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
title: Using handle
3+
---
4+
5+
# Using `handle`
6+
7+
[MODES: framework]
8+
9+
<br/>
10+
<br/>
11+
12+
You can build dynamic UI elements like breadcrumbs based on your route hierarchy using the [`useMatches`][use-matches] hook and [`handle`][handle] route exports.
13+
14+
## Understanding the Basics
15+
16+
React Router provides access to all route matches and their data throughout your component tree. This allows routes to contribute metadata through the `handle` export that can be rendered by ancestor components.
17+
18+
The `useMatches` hook combined with `handle` exports enables routes to contribute to rendering processes higher up the component tree than their actual render point. While we'll use breadcrumbs as an example, this pattern works for any scenario where you need routes to provide additional information to their ancestors.
19+
20+
## Defining Route `handle`s
21+
22+
We'll use a route structure like the following:
23+
24+
```ts filename=app/routes.ts
25+
import { route } from "@react-router/dev/routes";
26+
27+
export default [
28+
route("parent", "./routes/parent.tsx", [
29+
route("child", "./routes/child.tsx"),
30+
]),
31+
] satisfies RouteConfig;
32+
```
33+
34+
Add a `breadcrumb` property to the "parent" route's `handle` export. You can name this property whatever makes sense for your use case.
35+
36+
```tsx filename=app/routes/parent.tsx
37+
import { Link } from "react-router";
38+
39+
export const handle = {
40+
breadcrumb: () => <Link to="/parent">Some Route</Link>,
41+
};
42+
```
43+
44+
You can define breadcrumbs for child routes as well:
45+
46+
```tsx filename=app/routes/child.tsx
47+
import { Link } from "react-router";
48+
49+
export const handle = {
50+
breadcrumb: () => (
51+
<Link to="/parent/child">Child Route</Link>
52+
),
53+
};
54+
```
55+
56+
## Using Route `handle`s
57+
58+
Use the `useMatches` hook in your root layout or any ancestor component to collect and render the components defined in the `handle` export(s):
59+
60+
```tsx filename=app/root.tsx lines=[7,11,22-31]
61+
import {
62+
Links,
63+
Meta,
64+
Outlet,
65+
Scripts,
66+
ScrollRestoration,
67+
useMatches,
68+
} from "react-router";
69+
70+
export function Layout({ children }) {
71+
const matches = useMatches();
72+
73+
return (
74+
<html lang="en">
75+
<head>
76+
<Meta />
77+
<Links />
78+
</head>
79+
<body>
80+
<header>
81+
<ol>
82+
{matches
83+
.filter(
84+
(match) =>
85+
match.handle && match.handle.breadcrumb,
86+
)
87+
.map((match, index) => (
88+
<li key={index}>
89+
{match.handle.breadcrumb(match)}
90+
</li>
91+
))}
92+
</ol>
93+
</header>
94+
{children}
95+
<ScrollRestoration />
96+
<Scripts />
97+
</body>
98+
</html>
99+
);
100+
}
101+
102+
export default function App() {
103+
return <Outlet />;
104+
}
105+
```
106+
107+
The `match` object is passed to each breadcrumb function, giving you access to `match.data` (from loaders) and other route information to create dynamic breadcrumbs based on your route's data.
108+
109+
This pattern provides a clean way for routes to contribute metadata that can be consumed and rendered by ancestor components.
110+
111+
## Additional Resources
112+
113+
- [`useMatches`][use-matches]
114+
- [`handle`][handle]
115+
116+
[use-matches]: ../api/hooks/useMatches
117+
[handle]: ../start/framework/route-module#handle

0 commit comments

Comments
 (0)