Add the Navigation

Beta

These docs rely on Slice Machine, which is in active development and subject to change. Content Relationships are not currently supported with Slices.

This article will introduce doing queries outside the Slice Zone and configuring custom types in Prismic. We'll show you how to handle the top navigation in your Prismic repository and Next.js app.


See the Navigation Model

Looking at the top navigation, you can see that the model will be pretty simple. We don't know how many links we might need in the future, so we'll need to use a Group field to handle our links. Inside the Group field, we'll need:

  • A Link field to link to internal content
  • A Rich text field for the labels

Create a Menu Type and Add Content

Menus are handled outside the Slice Zone. So to be able to create a menu for your application you will need to create a 'menu' custom type in Prismic, add your menu links, and query your content.

In this example, we have created a single type Custom Type for the menu as we won't be creating many versions of the document. We have a Title field and a Group field inside the menu type. In the Group field, we added a Link field and a Rich Text field. This way, you can add as many links as you need. From here you can create a new menu document in your dashboard and add your content.

You can copy the full menu JSON below:

Copy
{
  "Main" : {
    "title" : {
      "type" : "StructuredText",
      "config" : {
        "placeholder" : "Menu title...",
        "single" : "heading1"
      }
    },
    "menu_links" : {
      "type" : "Group",
      "config" : {
        "fields" : {
          "label" : {
            "type" : "StructuredText",
            "config" : {
              "single" : "paragraph",
              "label" : "Link Label",
              "placeholder" : "Link Label..."
            }
          },
          "link" : {
            "type" : "Link",
            "config" : {
              "label" : "Link",
              "placeholder" : "Select a Link..."
            }
          }
        },
        "label" : "Menu Links"
      }
    }
  }
}

You'll see in the video below that we copy the content model for the menu, then create a menu Custom Type and paste the JSON into the JSON editor. Then head over to the document writing room and add your document links and link labels.


Query the Menu Content

Now, heading back to the project code, we're going to query the menu with getInitialProps in the _app.js file, call the query in the layout, and create the menu component. All of this is explained in the nav bars, footers, and menus article. The only difference will be in the styling we include for our component.

Create your Menu Query

Open the _app.js file. Then, query for the single instance of the Custom Type "menu" using the query helper function getSingle. This query will be located inside the getInitialProps fetching method. Then, pass the menu as props to the <Component /> in the render method.

Copy
import "../styles/globals.css";
import React from 'react'
import NextApp from 'next/app'
import { Client } from "../prismic-configuration";

export default class MyApp extends NextApp {
  static async getInitialProps(appCtx) {
    const client = Client();
    const menu = (await client.getSingle("menu")) || {};
    return {
      props: {
        menu: menu
      },
    };
  }

  render() {
    const { Component, pageProps, props } = this.props
    return (
      <Component {...pageProps} menu={props.menu} />
    )
  }
}

Call the Query in the Layout.js

Create a components folder in your Next.js project and add the Layout.js file inside of it. In this file, you can retrieve the menu from the props and pass it to the HeaderPrismic.js component. Make sure that all the imports match your project routes.

Copy
import React from "react";
import Head from "next/head";
import HeaderPrismic from './HeaderPrismic'

const Layout = ({ children, menu }) => {
  return (
    <div>
      <Head>
        <title> Prismic Next.js Multi Page Website </title>
      </Head>
      <HeaderPrismic menu={menu} />
      <main>{children}</main>
    </div>
  );
};

export default Layout;

Code and Style the Menu

Below is our menu component called HeaderPrismic.js that we created in the components folder. We can now access the data from Layout.js with menuLinks so that we can code and style it.

Copy
import React from "react";
import { RichText } from 'prismic-reactjs'
import { Link } from 'prismic-reactjs'

const HeaderPrismic = ({ menu = [] }) => (
    <header className="site-header">
      <a href="/" className="logo">
        {RichText.asText(menu.data.title)}
      </a>
      <Links menuLinks={menu.data.menu_links} />
      <style jsx>{`
        .site-header {
          height: 30px;
          padding: 20px 0;
          color: #484d52;
          font-weight: 700;
        }
        .site-header a {
          color: #484d52;
          font-weight: 700;
        }
        .site-header a:hover {
          color: #72767B;
        }
        .site-header .logo {
          display: inline-block;
          font-size: 22px;
          font-weight: 900;
        }
        @media (max-width: 1060px) {
          .site-header {
            padding-left: 20px;
            padding-right: 20px;
          }
        }
        @media (max-width: 767px) {
          .site-header {
            height: auto;
          }
          .site-header {
            position: absolute;
            left: 0;
            right: 0;
          }
          .site-header .logo {
            display: block;
            text-align: center;
          }
        `}</style>
    </header>
);

const Links = ({menuLinks}) => {
  if (menuLinks) {
    return (
      <nav>
        <ul>
          {menuLinks.map((menuLink, index) => (
            <li key={`menulink-${index}`}>
              <a href={Link.url(menuLink.link)}>
                {RichText.asText(menuLink.label)}
              </a>
            </li>
          ))}
        </ul>
        <style jsx>{`
          nav {
            float: right;
          }
          nav ul {
            margin: 0;
            padding-left: 0;
          }
          nav li {
            display: inline-block;
            margin-left: 40px;
          }
          nav li a {
            color: #484d52;
            font-weight: 700;
          }
          nav li a:hover {
            color: #72767B;
          }
          @media (max-width: 767px) {
            nav {
              float: none;
              text-align: center;
            }
            nav li {
              display: inline-block;
              margin-left: 10px;
              margin-right: 10px;
            }
          }
          `}</style>
      </nav>
    )
  }
  return null
}

export default HeaderPrismic;

Add the Layout to your Pages

Now that you've built your layout component, you can wrap all elements in the render of your page files, and pass the menu as props. Here we give you an example of the index.js file, but you can add it to every other page that you create.

Copy
import { Client } from "../prismic-configuration";
import SliceZone from "next-slicezone";
import { useGetStaticProps } from "next-slicezone/hooks";

import resolver from "../sm-resolver.js";
import Layout from "./../components/Layout";

const Page = (props) => {
  return (
    <Layout menu={props.menu}>
      <SliceZone {...props} resolver={resolver} />;
    </Layout>
  );
};

// Fetch content from prismic
export const getStaticProps = useGetStaticProps({
  client: Client(),
  uid: () => "home",
});

export default Page;

See your new Menu

Now all the hard work is done, simply run your project:

  • npm
  • Yarn
Copy
npm run dev
Copy
yarn dev

Boom! Simple as that you've got a website menu :)


Next and Previous articles


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.