Returns an array of all matched routes from the root layout down to the current page. Each match includes the route’s loader data, params, and route ID.
This is useful for:
loaderData is typed unknown, since a match can come from any route. Give it the type of the loader that produced it:
import { useMatches } from 'one'
type PageData = { title?: string }
function Breadcrumbs() { const matches = useMatches()
return ( <nav> {matches.map((match) => ( <a key={match.routeId} href={match.pathname}> {(match.loaderData as PageData | undefined)?.title ?? match.routeId} </a> ))} </nav> )}A common use case is accessing a layout’s loader data from a page component:
import { useMatches } from 'one'import type { DocsLayoutData } from './_layout'
// in a page componentfunction DocsPage() { const matches = useMatches()
// find the docs layout match const docsLayout = matches.find((m) => m.routeId.includes('docs/_layout')) const navItems = (docsLayout?.loaderData as DocsLayoutData | undefined)?.navItems
return ( <div> <Sidebar items={navItems} /> {/* page content */} </div> )}Layouts can access their child page’s loader data to render things like a table of contents:
import { Slot, useMatches } from 'one'
export async function loader() { return { navItems: await fetchDocsNav(), }}
export type DocsLayoutData = Awaited<ReturnType<typeof loader>>
type DocsPageData = { headings: { id: string; title: string }[] }
export default function DocsLayout() { const matches = useMatches()
// the last match is the current page const pageMatch = matches[matches.length - 1] const headings = (pageMatch?.loaderData as DocsPageData | undefined)?.headings
return ( <div> <Sidebar /> <main> <Slot /> </main> <TableOfContents headings={headings} /> </div> )}Each match in the array has this shape:
type RouteMatch = { routeId: string // e.g., './docs/_layout.tsx' pathname: string // e.g., '/docs/intro' params: Record<string, string | string[]> // URL params like { slug: 'intro' } loaderData: unknown // data from the route's loader}Find a specific route’s match by its route ID:
import { useMatch } from 'one'import type { DocsLayoutData } from './docs/_layout'
function Component() { // find a specific layout's data const docsMatch = useMatch('./docs/_layout.tsx') const navItems = (docsMatch?.loaderData as DocsLayoutData | undefined)?.navItems}Returns undefined if the route is not in the current match list.
Get the current page’s match (the last/deepest match):
import { Head, usePageMatch } from 'one'
type PageMeta = { title?: string; description?: string }
function Layout() { const pageMatch = usePageMatch() const { title, description } = (pageMatch?.loaderData as PageMeta | undefined) ?? {}
return ( <Head> <title>{title}</title> <meta name="description" content={description} /> </Head> )}Edit this page on GitHub.