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

For our Menu, we'll create one document which we'll query once and display everywhere. So in the Custom Types section, create a single type Custom Type for the menu as we'll only be creating one version of the document. Call it 'Menu' with the API ID menu.

In the Menu Type's Static Zone add a Title field and a Group field. In the Group field, add a Link field and a Rich Text field. This will allow you to add as many links as you need.

You can see all the API IDs for these fields below:

Field

API ID

Title

title

Group

menu_links

Link

link

Rich Text

label

Then click 'Save to File System' + 'Push to Prismic' and jump over to the Prismic Dashboard. From here you can create a new Menu document and add your links and click 'Save' + 'Publish'.

You can see how your Menu Custom Type should look below:

The Menu Custom Type
The Menu Custom Type

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 Header.js component. Make sure that all the imports match your project routes.

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

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

export default Layout;

Code and Style the Menu

Below is our menu component called Header.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 Header = ({ 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 Header;

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.

next-slicezone version

The following examples use the latest version of the next-slicezone package, which changes how values from the parameters are called. Learn more about next-slicezone's Lifecycle hooks.

To install this run npm install next-slicezone@latest

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 Home = (props) => {
  return (
    <Layout menu={props.menu}>
      <SliceZone {...props} resolver={resolver} />;
    </Layout>
  );
};

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

export default Home;

Update your Route Resolver

The last thing to is to update your Route Resolver in your prismic-configuration.js file. We use the Route Resolver to build links for Prismic documents in our project. It's also used for building routes when your project is 'Statically' deployed. You can learn more about how to defining the Route Resolver here.

So, because we added a new 'Home Page' Custom Type, in the Route Resolver we'll need to add this type and the path to follow when a link is created for this document type. Open the prismic-configuration.js file in the base of your project, find the Router object and the following info:

Copy
export const Router = {
  routes: [
    {
      "type":"page",
      "path":"/:uid"
    },
    {
      "type":"home-page",
      "path":"/"
    },
  ],
  href: (type) => {
    const route = Router.routes.find(r => r.type === type);
    return route && route.href;
  }
};

Keep this updated

Every time you add a new Custom Type to your project you'll need to update this field if you want your links and your Prismic Previews to work.


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.