From 0ad1823506b779b356de9cd84c8b07f1583f9f20 Mon Sep 17 00:00:00 2001 From: Brooks Lybrand Date: Tue, 30 Sep 2025 17:45:05 -0500 Subject: [PATCH 1/2] docs: add route metadata guide --- docs/how-to/route-metadata.md | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docs/how-to/route-metadata.md diff --git a/docs/how-to/route-metadata.md b/docs/how-to/route-metadata.md new file mode 100644 index 0000000000..1bd3b87618 --- /dev/null +++ b/docs/how-to/route-metadata.md @@ -0,0 +1,105 @@ +--- +title: Route Metadata +--- + +# Route Metadata + +[MODES: framework] + +
+
+ +You can build dynamic UI elements like breadcrumbs based on your route hierarchy using the [`useMatches`][use-matches] hook and [`handle`][handle] route exports. + +## Understanding the Basics + +React Router provides access to all route matches and their data throughout your component tree. This allows routes to contribute metadata that can be rendered by ancestor components. + +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 metadata. + +## Defining Route Metadata + +Add a `breadcrumb` property to your route's `handle` export. You can name this property whatever makes sense for your use case. + +```tsx filename=app/routes/parent.tsx +import { Link } from "react-router"; + +export const handle = { + breadcrumb: () => Some Route, +}; +``` + +You can define breadcrumbs for child routes as well: + +```tsx filename=app/routes/parent.child.tsx +import { Link } from "react-router"; + +export const handle = { + breadcrumb: () => ( + Child Route + ), +}; +``` + +## Using Route Metadata + +Use the `useMatches` hook in your root layout or any ancestor component to collect and render the metadata: + +```tsx filename=app/root.tsx lines=[7,11,22-31] +import { + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, + useMatches, +} from "react-router"; + +export function Layout({ children }) { + const matches = useMatches(); + + return ( + + + + + + +
+
    + {matches + .filter( + (match) => + match.handle && match.handle.breadcrumb, + ) + .map((match, index) => ( +
  1. + {match.handle.breadcrumb(match)} +
  2. + ))} +
+
+ {children} + + + + + ); +} + +export default function App() { + return ; +} +``` + +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. + +This pattern provides a clean way for routes to contribute metadata that can be consumed and rendered by ancestor components. + +## Additional Resources + +- [`useMatches`][use-matches] +- [`handle`][handle] + +[use-matches]: ../api/hooks/useMatches +[handle]: ../start/framework/route-module#handle From 9a68258d343adcf6220923e849f6bc1c4a88ed20 Mon Sep 17 00:00:00 2001 From: Brooks Lybrand Date: Wed, 1 Oct 2025 12:01:48 -0500 Subject: [PATCH 2/2] update breadcrumbs guide to be more focused on `handle` instead of "metadata" --- .../{route-metadata.md => using-handle.md} | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) rename docs/how-to/{route-metadata.md => using-handle.md} (76%) diff --git a/docs/how-to/route-metadata.md b/docs/how-to/using-handle.md similarity index 76% rename from docs/how-to/route-metadata.md rename to docs/how-to/using-handle.md index 1bd3b87618..76d5f7e6af 100644 --- a/docs/how-to/route-metadata.md +++ b/docs/how-to/using-handle.md @@ -1,8 +1,8 @@ --- -title: Route Metadata +title: Using handle --- -# Route Metadata +# Using `handle` [MODES: framework] @@ -13,13 +13,25 @@ You can build dynamic UI elements like breadcrumbs based on your route hierarchy ## Understanding the Basics -React Router provides access to all route matches and their data throughout your component tree. This allows routes to contribute metadata that can be rendered by ancestor components. +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. -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 metadata. +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. -## Defining Route Metadata +## Defining Route `handle`s -Add a `breadcrumb` property to your route's `handle` export. You can name this property whatever makes sense for your use case. +We'll use a route structure like the following: + +```ts filename=app/routes.ts +import { route } from "@react-router/dev/routes"; + +export default [ + route("parent", "./routes/parent.tsx", [ + route("child", "./routes/child.tsx"), + ]), +] satisfies RouteConfig; +``` + +Add a `breadcrumb` property to the "parent" route's `handle` export. You can name this property whatever makes sense for your use case. ```tsx filename=app/routes/parent.tsx import { Link } from "react-router"; @@ -31,7 +43,7 @@ export const handle = { You can define breadcrumbs for child routes as well: -```tsx filename=app/routes/parent.child.tsx +```tsx filename=app/routes/child.tsx import { Link } from "react-router"; export const handle = { @@ -41,9 +53,9 @@ export const handle = { }; ``` -## Using Route Metadata +## Using Route `handle`s -Use the `useMatches` hook in your root layout or any ancestor component to collect and render the metadata: +Use the `useMatches` hook in your root layout or any ancestor component to collect and render the components defined in the `handle` export(s): ```tsx filename=app/root.tsx lines=[7,11,22-31] import {