Navbars, Footers, and Menus

As discussed in the Query content from the CMS article, to query content outside the SliceZone of your document, you need to perform another query. For menus or footers, it's a little different as you'll not want to query the menu on every page; we'll show you the best practice for doing this below.


Model the menu in Prismic

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.

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"
      }
    }
  }
}

Query the menu

Open the _app.js file. Then query for the single instance of the Custom Type "menu" using the query helper function getSingle from the Javascript development kit. 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 React from 'react'
import Prismic from '@prismicio/client'
import NextApp from 'next/app'

// Update your-repo-name with the name of your repository.
const apiEndpoint = 'https://your-repo-name.cdn.prismic.io/api/v2'
const Client = Prismic.client(apiEndpoint, { req })

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

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

Create the components

Create a /components folder in your Next.js project and add these files inside of it:

  • Layout.js
  • Header.js

Create a Layout

In the Layout.js file, retrieve the menu from the props in this file 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'

// Update the path for your Header component.
import Header from '../path-to-your-header-component'

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

export default Layout;

Create a header

In your Header.js file, access the menuLinks props from Layout.js and use them to create the menu,

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

const Header = ({ menu = [] }) => (
  <header>
    <a href="/">{RichText.asText(menu.data.title)}</a>
    <Links menuLinks={menu.data.menu_links} />
  </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>
      </nav>
    );
  }
  return null;
};

export default Header;

Add the layout to your pages and pass it props

Now, wrap all your pages with the Layout component and pass the menu as props.

Here we give you an example of the [uid].js file, but you can add it to every other page you create, like the index.js that will be your homepage.

next-slicezone version

The following examples use the latest version of the next-slicezone package (0.1.0-alpha.0), 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@0.1.0-alpha.0

Copy
// Example 〜/pages/[uid].js file

import Prismic from '@prismicio/client'
import SliceZone from 'next-slicezone'
import { useGetStaticProps, useGetStaticPaths } from 'next-slicezone/hooks'

// Update your-repo-name with the name of your repository.
const apiEndpoint = 'https://your-repo-name.cdn.prismic.io/api/v2'
const Client = Prismic.client(apiEndpoint, { req })

// Update the paths for your component files.
import resolver from '../path-to-your-resolver-config'
import Layout from '../path-to-your-layout-component'

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

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

export const getStaticPaths = useGetStaticPaths({
  client: Client(),
  formatPath: (prismicDocument) => {
    return {
      params: {
        uid: prismicDocument.uid,
      },
    }
  },
});

export default Page;

That's it, now you have a Layout with a menu that you can modify to your liking.


Related 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.