Adding schemas to the router of a Next.js 13 app is a helpful feature that can

Summary:

In Next.js 13, the /app router's new changes to layout and page routing have altered how we add content to the <head>. The challenge now is how to include a schema script on each page. Next.js automatically combines <head> tags from all layout or page components into a single <head>.

The Objective

Like any SEO-friendly website, I aim to embed a schema script in the head of every page.

A Journey Back

In the past, this task was as simple as inserting it in the <head> section like this:

<!-- index.html -->
<head>
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      // ... rest of the script
    }
  </script>
</head>

However, with the Next.js /pages directory, it required using the dangerouslySetInnerHTML attribute, which felt awkward but got the job done.

// index.tsx
import Head from 'next/head'
export default function Page() {
  return (
    <Head>
      <script id="schema" type="application/ld+json" dangerouslySetInnerHTML={{__html: `
        {
          "@context": "https://schema.org",
          // ... rest of the script
        }
      `}} />
    </Head>
  )
}

The Challenge

With the recent implementation of the /app router, configuring metadata has become easier without directly importing <head> using next/head. However, using the next/head component in the /app router is discouraged.

This raises the question...

How can we access the <head> for individual pages?

I hoped that the Next.js team would have addressed this by adding schema support to the new metadata variable or creating a separate one, but no such plans seem to be in place yet.

When attempting to add a <head> to the page, unfortunately, it does not merge properly into the overall <head>. One potential solution could involve adding the schema to each layout, although having a unique layout for every page could be cumbersome.

I welcome any suggestions or ideas.

Answer №1

Official Answer from Next.js Team

To learn more about optimizing metadata using JSON-LD, you can refer to the official documentation provided by the Next.js team here. (Note that placing the schema in the <head> is not mandatory, as illustrated in the code snippet)

Implementation Example

By utilizing a JS object and incorporating a <script> tag, it becomes possible to include the JSON-LD on any desired page.

// page.tsx

export default async function Page({ params }) {
  const product = await getProduct(params.id)
 
  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.name,
    image: product.image,
    description: product.description,
  }
 
  return (
    <section>
      {/* Embed JSON-LD into your page */}
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      {/* ... */}
    </section>
  )
}

Answer №2

Perhaps you already have the solution, but for those of us still searching for answers to the same issue:

import Head from 'next/head';

function ProductPage() {
  function addProductJsonLd() {
    return {
      __html: `{
      "@context": "https://schema.org/",
      "@type": "Product",
      "name": "Executive Anvil",
      "image": [
        "https://example.com/photos/1x1/photo.jpg",
        "https://example.com/photos/4x3/photo.jpg",
        "https://example.com/photos/16x9/photo.jpg"
       ],
      "description": "Sleeker than ACME's Classic Anvil, the Executive Anvil is perfect for the business traveler looking for something to drop from a height.",
      "sku": "0446310786",
      "mpn": "925872",
      "brand": {
        "@type": "Brand",
        "name": "ACME"
      },
      "review": {
        "@type": "Review",
        "reviewRating": {
          "@type": "Rating",
          "ratingValue": "4",
          "bestRating": "5"
        },
        "author": {
          "@type": "Person",
          "name": "Fred Benson"
        }
      },
      "aggregateRating": {
        "@type": "AggregateRating",
        "ratingValue": "4.4",
        "reviewCount": "89"
      },
      "offers": {
        "@type": "Offer",
        "url": "https://example.com/anvil",
        "priceCurrency": "USD",
        "price": "119.99",
        "priceValidUntil": "2020-11-20",
        "itemCondition": "https://schema.org/UsedCondition",
        "availability": "https://schema.org/InStock"
      }
    }
  `,
    };
  }
  return (
    <div>
      <Head>
        <title>My Product</title>
        <meta
          name="description"
          content="Super product with free shipping."
          key="desc"
        />
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={addProductJsonLd()}
          key="product-jsonld"
        />
      </Head>
      <h1>My Product</h1>
      <p>Super product for sale.</p>
    </div>
  );
}

export default ProductPage;

For further information, please refer to the next.js documentation on this link.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

After the checkbox is clicked, I must send a boolean value to the function through the input flag in AngularJS

<input class="bx--toggle" id="toggle-view" type="checkbox" ng-model="vm.monthView" ng-change="vm.getRelevantData()" ng-attr-data-modal-target="{{vm.alertForSaveAll ? '#add-save-all-alert-modal': 'undefined'}}"> Within this p ...

Retrieve the dimensions of an image once rendering is complete, using Angular

I'm currently working on obtaining the rendered size of an image within a component. By utilizing the (load) event, I can capture the size of the image as it appears at that particular moment (pic1), as well as its "final" size after the page has fini ...

Determine total number of covid-19 cases with JavaScript

I am looking to incorporate a real-time COVID-19 total cases tracker for Russia on my website. In order to achieve this, I am sending a request to using the following script: function httpGet(theUrl) { var xmlHttp = new XMLHttpRequest(); xmlHttp.o ...

RTK Query may sometimes encounter undefined values when fetching data

I am new to using Redux and facing an issue while trying to display data in a Material UI Select. When I try to show the user's name, it works perfectly, but when I do the same for the partner's data, they appear as undefined. In my server index ...

ReactJs Unicode Integration with ID3 JS

I am working on a React Project that involves using an input type = "file" to upload music files. I am able to extract tags using ID3 Js, but the result is displayed in this format: https://i.stack.imgur.com/192co.png Is there a way to convert ...

Is there a way to expand the clickable area of JQuery sliders?

Check out some of the jquery ui sliders here One issue I am facing is that when you click the slider bar, the tic jumps to that exact part. This can be problematic because the bar is quite thin, making it easy to miss when trying to click on it. I want to ...

display the table without providing a preview

Hey everyone, I am currently utilizing vue.js to develop a table and I am looking for a way to add a button that can print the data in the table without displaying a preview dialog. What modifications should I make to my javascript code in vue? Here is an ...

Encase the event handler within JQuery

Here's an example of inputs with OnBlur event handlers: <input name="abc" tabIndex="5" class="datetime" onblur="if (CheckMode(this))__doPostBack('abc',''); else return false;" /> Now, in JQuery Form ready function, I want ...

Tips for incorporating dynamic content into React Material UI expansion panels while maintaining the ability to have only one tab active at a time

I'm working on a project using WebGL and React where I generate a list of users from mock data upon clicking. To display this content in an accordion format, I decided to use Material UI's expansion panel due to my positive past experience with ...

utilize jQuery and AngularJS to transform a JSON object into a nested JSON structure

Is there a way to convert my current JSON file into a nested JSON structure like the one below? I've attempted various methods (How to convert form input fields to nested JSON structure using jQuery), but I'm not achieving the desired outcome. Ca ...

Ensure AngularJS ng-show and ng-hide are more secure

When using AngularJS, my goal is to conceal an element so that only authenticated users can access it. Although the ng-hide directive works, there is a vulnerability where someone could modify the class assigned to the element (ng-hide) using Developer To ...

bcrypt is failing to return a match when the password includes numeric characters

I've integrated node-bcrypt with PostgreSQL (using Sequelizejs) to securely hash and store passwords. In the process, the user's password undergoes hashing within a beforeValidate hook as shown below: beforeValidate: function(user, model, cb) { ...

Creating an array of objects by parsing JSON using the jQuery .each() method

I am attempting to generate an array of objects by parsing a JSON file. Here is the pertinent code: //president object constructor function president(a_presName, a_presDates, a_presNick, a_presImage) { this.presName=a_presName; this.presDates=a_pr ...

struggle with converting JSON string into an array from server

After receiving JSON data from the server, I attempted to convert it into an array using: JSON.parse(response.data.blocks) However, I encountered this error: SyntaxError: Unexpected token o in JSON at position 1 at JSON.parse (<an ...

How can I add a comma after every third number in a react component?

I am currently developing an input feature where I need to insert a comma after every 3 numbers, such as (352,353,353). The challenge is to display this format in a text field. Since I am new to working with React, I would appreciate any guidance on how to ...

customize Form Modal Bootstrap with AJAX Chained Dropdown for pre-selected options

I am facing an issue with a chained dropdown on a bootstrap modal, Here is the code snippet: function changeDetail(id) { var id = id; $('#edit').prop('hidden', true); $('#modal_form').prop('hidden', fa ...

Deduce the generic types of conditional return based on object property

My goal is to determine the generic type of Model for each property. Currently, everything is displaying as unknown[] instead of the desired types outlined in the comments below. playground class Model<T> { x?: T } type ArgumentType<T> = T ...

Electron JS-powered app launcher for seamless application launching

Currently, I am working on a project to develop an application launcher using HTML, CSS, and JS with Electron JS. Each application is linked through an a href tag that directs users to the respective application path. If a normal link is used in the a hr ...

What is the best way to access an excel file using JavaScript and Protractor?

Is it possible to read an Excel file dynamically in JavaScript and iterate through cell values using row and column counts, without converting it into a JSON object? I have searched through several posts on Stack Overflow but have not found a solution yet. ...

Is there a way to create Angular components sourced from an external library using JavaScript?

I'm currently developing an Angular project and leveraging an external component library called NGPrime. This library provides me with a variety of pre-built components, including <p-button> (which I am using in place of a standard <button> ...