Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for How to Build Dynamic Breadcrumbs in Remix
Piotr Kulpinski
Piotr Kulpinski

Posted on • Originally published atkulpinski.dev

     

How to Build Dynamic Breadcrumbs in Remix

In Remix, building dynamic breadcrumbs that reflect your route hierarchy is straightforward. This tutorial will guide you through leveraging theuseMatches andhandle capabilities to achieve this.

We'll also cover how to add schema metadata to your breadcrumbs for better SEO and social sharing.

The Basics

Breadcrumbs are a navigation aid that helps users understand their current location within a website. They typically appear horizontally at the top of a page and show the hierarchy of the current page in relation to the site structure.

Here's an example of what breadcrumbs code could look like:

<olitemscopeitemtype="https://schema.org/BreadcrumbList"><liitemprop="itemListElement"itemscopeitemtype="https://schema.org/ListItem"><ahref="https://example.com/"itemprop="item"><spanitemprop="name">Home</span></a><metaitemprop="position"content="1"/></li><liitemprop="itemListElement"itemscopeitemtype="https://schema.org/ListItem"><ahref="https://example.com/posts"itemprop="item"><spanitemprop="name">Posts</span></a><metaitemprop="position"content="2"/></li><liitemprop="itemListElement"itemscopeitemtype="https://schema.org/ListItem"><ahref="https://example.com/posts/slug"itemprop="item"><spanitemprop="name">Post Title</span></a><metaitemprop="position"content="3"/></li></ol>
Enter fullscreen modeExit fullscreen mode

Now, let's see how to build dynamic breadcrumbs in Remix.

Defining the Breadcrumbs Components

Let's start by creating the necessary component that we'll later use to render the breadcrumbs.

We'll need aBreadcrumbs component to render the list of breadcrumbs and aBreadcrumbsItem component to render each breadcrumb item.

Start by defining a wrapper component that will list all of the breadcrumbs.

// app/components/Breadcrumbs.tsximport{UIMatch,useMatches}from"@remix-run/react"import{Fragment,HTMLAttributes}from"react"typeBreadcrumbMatch=UIMatch<Record<string,unknown>,{breadcrumb:(data?:unknown)=>JSX.Element}>exportconstBreadcrumbs=({...props}:HTMLAttributes<HTMLElement>)=>{constmatches=(useMatches()asunknownasBreadcrumbMatch[]).filter(({handle})=>handle?.breadcrumb)return(<olitemScopeitemType="https://schema.org/BreadcrumbList"className="flex flex-wrap items-center gap-2.5"{...props}>{matches.map(({handle,data},i)=>(<Fragmentkey={i}><liclassName="contents"itemProp="itemListElement"itemScopeitemType="https://schema.org/ListItem">{i>0&&<spanclassName="text-sm">/</span>}{handle.breadcrumb(data)}<metaitemProp="position"content={`${i+1}`}/></li></Fragment>))}</ol>)}
Enter fullscreen modeExit fullscreen mode

In the example above, we're using theuseMatches hook to get the current route matches. We then filter the matches to only include those that have abreadcrumb handle. We will define this handle in the routes where we want to include a breadcrumb. We then iterate over the matches and render the breadcrumb component for each match.

You may have noticed that we're also passing adata prop to thehandle.breadcrumb function. This is because thebreadcrumb handle can accept data from the route loader. We'll see how to pass data to the breadcrumb handle in the next section.

Next, let's define theBreadcrumbsItem component that we'll use to render each breadcrumb item.

// app/components/BreadcrumbsItem.tsximport{Link}from"@remix-run/react"import{HTMLAttributes}from"react"exportconstBreadcrumbsItem=({children,...props}:HTMLAttributes<HTMLElement>)=>{return(<Linkto={props.href}itemProp="item"{...props}><spanitemProp="name">{children}</span></Link>)}
Enter fullscreen modeExit fullscreen mode

Now that we have our components, let's define the breadcrumbs in our routes.

Defining the Breadcrumbs handles in the Routes

In the routes where you want to include breadcrumbs, you need to define abreadcrumb handle that will render the breadcrumb item.

For example, let's define the following routes:

  • / - Home
  • /posts - Posts
  • /posts/$slug - Post Details
// app/routes/index.tsximport{BreadcrumbsItem}from"~/components/BreadcrumbsItem"exportconsthandle={breadcrumb:()=><BreadcrumbsItemto="/">Home</BreadcrumbsItem>,}exportdefaultfunctionIndex(){return<h1>Home</h1>}
Enter fullscreen modeExit fullscreen mode
// app/routes/posts/index.tsximport{BreadcrumbsItem}from"~/components/BreadcrumbsItem"exportconsthandle={breadcrumb:()=><BreadcrumbsItemto="/posts">Posts</BreadcrumbsItem>,}exportdefaultfunctionPosts(){return<h1>Posts</h1>}
Enter fullscreen modeExit fullscreen mode
// app/routes/posts.$slug.tsximport{json,typeLoaderFunctionArgs}from"@remix-run/node"import{useLoaderData}from"@remix-run/react"import{BreadcrumbsItem}from"~/components/BreadcrumbsItem"exportconsthandle={breadcrumb:(data:{title:string;slug:string})=>(<BreadcrumbsItemto={`/posts/${data.slug}`}>{data.title}</BreadcrumbsItem>),}exportconstloader=({params}:LoaderFunctionArgs)=>{constpost={title:"Example Post",slug:"example-post",}returnjson(post)}exportdefaultfunctionPost(){const{title}=useLoaderData<typeofloader>()return<h1>{title}</h1>}
Enter fullscreen modeExit fullscreen mode

In the last route, we're using theloader function to fetch the post data. We then pass this data to thebreadcrumb handle to render the breadcrumb item. This allows us to dynamically generate the breadcrumb item based on the post data.

Conclusion

Hopefully, this guide has helped you understand how to implement breadcrumbs in your Remix application.

If you're interested to see how breadcrumbs can be implemented in a real-world application, you can check out theOpenAlternative project, or check out thesource code.

If you have any questions or need further clarification, feel free to reach out to me onTwitter.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

More fromPiotr Kulpinski

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp