Creating Breadcrumb Structured Data for your React/Typescript Website

Recently, I've been working a my new website called Discaper. My vision for Discaper is that it will hopefully become the Zomato of Escape Rooms! Meaning that it'll be the place you go to to find the most suitable escape room for you.

Anyway, I've implemented a breadcrumb component for Discaper that helps users navigate throughout the website. For example, for the Assassin in the Club Escape Room, has the breadcrumbs of: Home -> Australia -> NSW -> Sydney -> Escape Hunt Sydney -> Assassin in the Pub. Clicking on any section of the breadcrumb will then show you all places/rooms in the next level contained within it. For example, clicking Australia will show you all states that have escape rooms in Australia. Or clicking Escape Hunt Sydney will show you all the escape rooms that are operated by Escape Hunt Sydney.

I've noticed on other big websites that results in Google Search give a neat little breadcrumb result. For example, if I searched Indu (a restaurant I went to last weekend) on Google, Zomato's search result looks like:

You can see Zomato has a nice little breadcrumb result: https://www.zomato.com › Australia › Sydney › City of Sydney › CBD. I wanted this for Discaper! Currently a result on Discaper looks like:

It turns out there's a relatively easy way to get these search results. You have to implement something called Structured Data and search engines consume this to give neat little results like Zomato.

Discaper is made using NextJS, React and TypeScript and I wanted to document how I got structured data working for Discaper using these technologies!

Structured Data Breadcrumb Component

For this example, let's say we want to display the breadcrumbs for our "Place", which looks like: Home -> Country -> State -> Region -> Place.

Let's also say we have our breadcrumb list with an interface of

export interface IBreadcrumb {
  description: string;
  url: string;
}

and we have our breadcrumb data for our place as:

  const breadcrumbList: IBreadcrumb[] = [
    {
      description: "Home",
      url: "/"
    },
    {
      description: "Australia",
      url: "/australia"
    },
    {
      description: "NSW",
      url: "/australia/nsw"
    },
    {
      description: "Sydney",
      url: "/australia/nsw/sydney"
    },
    {
      description: "Harvey's place",
      url: "/australia/nsw/sydney/harveys-place"
    }
  ];

The first thing I did was went to the Google documentation for how they wanted the BreadCrumb structured data to be... structured. This documentation gave me an overview, but I found the examples to be lacking.

So, I looked for a concrete example and found one here on Stack Overflow. This post basically gave the outline of what a valid structured data breadcrumb HTML should look like:

<ol itemscope itemtype="http://schema.org/BreadcrumbList">
  <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
    <a itemscope itemtype="http://schema.org/Thing" itemprop="item" href="/" itemid="/">
      <span itemprop="name">Root page</span>
    </a>
    <meta itemprop="position" content="1" />
  </li>
  <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
    <a itemscope itemtype="http://schema.org/Thing" itemprop="item" href="/category" itemid="/category">
      <span itemprop="name">Category page</span>
    </a>
    <meta itemprop="position" content="2" />
  </li>
  <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
    <span itemscope itemtype="http://schema.org/Thing" itemprop="item" itemid="/category/this-page">
      <span itemprop="name">This page</span>
    </span>
    <meta itemprop="position" content="3" />
  </li>
</ol>

User FlameStorm also outlined that you can use Google's Structured Data Testing Tool to find out whether your structured data is valid or not. Try pasting the above HTML into it!

Using this example, I created a component that allowed me to render the breadcrumbs that are structured data compliant (with Google at least).

I created the component BreadCrumb that looks like:

The gotchas here are to remember that, in React, attributes have different names to what they normally would be (took me a while to figure out why React wasn't rendering things correctly!).

So for example:

<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">

would be:

<li itemProp="itemListElement" itemScope={true} itemType="http://schema.org/ListItem">

in React.

Example usage

Let's use our component and see if our HTML is structured data compliant.

Rendering:

    <StructuredBreadcrumb breadcrumbList={breadcrumbList} />

Would give us:

<ol
  itemscope=""
  itemtype="http://schema.org/BreadcrumbList"
  class="breadcrumbs-container"
>
  <li
    itemprop="itemListElement"
    itemscope=""
    itemtype="http://schema.org/ListItem"
  >
    <a
      href="/"
      itemscope=""
      itemtype="http://schema.org/Thing"
      itemprop="item"
      itemid="/"
      ><span itemprop="name">Home</span></a
    ><meta itemprop="position" content="0" />
  </li>
  <li
    itemprop="itemListElement"
    itemscope=""
    itemtype="http://schema.org/ListItem"
  >
    <a
      href="/australia"
      itemscope=""
      itemtype="http://schema.org/Thing"
      itemprop="item"
      itemid="/australia"
      ><span itemprop="name">Australia</span></a
    ><meta itemprop="position" content="1" />
  </li>
  <li
    itemprop="itemListElement"
    itemscope=""
    itemtype="http://schema.org/ListItem"
  >
    <a
      href="/australia/nsw"
      itemscope=""
      itemtype="http://schema.org/Thing"
      itemprop="item"
      itemid="/australia/nsw"
      ><span itemprop="name">NSW</span></a
    ><meta itemprop="position" content="2" />
  </li>
  <li
    itemprop="itemListElement"
    itemscope=""
    itemtype="http://schema.org/ListItem"
  >
    <a
      href="/australia/nsw/sydney"
      itemscope=""
      itemtype="http://schema.org/Thing"
      itemprop="item"
      itemid="/australia/nsw/sydney"
      ><span itemprop="name">Sydney</span></a
    ><meta itemprop="position" content="3" />
  </li>
  <li
    itemprop="itemListElement"
    itemscope=""
    itemtype="http://schema.org/ListItem"
  >
    <a
      href="/australia/nsw/sydney/harveys-place"
      itemscope=""
      itemtype="http://schema.org/Thing"
      itemprop="item"
      itemid="/australia/nsw/sydney/harveys-place"
      ><span itemprop="name">Harvey's place</span></a
    ><meta itemprop="position" content="4" />
  </li>
</ol>

Putting this HTML into the Structured Data Testing Tool gives us a valid result!

If this helped, give https://gist.github.com/HarveyD/7964ac480fe7a6fbb0d85004d3959d39 a star :). Enjoy your breadcrumbs!

Also, put https://www.discaper.com/room/assassin-in-the-pub into the Google Structured Data Testing tool! Pretty cool right?

Update 25/08/2019: Assassin in the Pub now has the search result: