Navbars, Footers, and Menus

As we discussed in the 'Querying content from the CMS' article, to query content that is outside the SliceZone of your document (i.e. the body), you will 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 your 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"
      }
    }
  }
}

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 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 NextApp from 'next/app'
import { theme } from 'essential-slices'
import { ThemeProvider, BaseStyles } from 'theme-ui'
import { Client } from "../prismic";

export default class App extends NextApp {
  //calls page's `getInitialProps` 
  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 (
      <ThemeProvider theme={theme}>
        <BaseStyles>
           // Pass menu as props in the component
           <Component {...pageProps} menu={props.menu} />
        </BaseStyles>
      </ThemeProvider>
    )
  }
}

Create the Components

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

  • Layout.js
  • HeaderPrismic.js

Call the Query in the Layout.js

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 '~/components/HeaderPrismic'

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

export default Layout;

Create the Menu Component

Below is our menu component called HeaderPrismic.js where we can now access the data from Layout.js with menuLinks and implement it.

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

const HeaderPrismic = ({ 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 HeaderPrismic;

Add the Layout to your Pages and Pass them Props

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 [uid].js file, but you can add it to every other page that you create, like the index.js that will be your homepage.

Copy
import { Client } from "../prismic";
import SliceZone from "next-slicezone";
import { useGetStaticProps, useGetStaticPaths } 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: ({ params }) => params.uid,
});

export const getStaticPaths = useGetStaticPaths({
  client: Client(),
  type: "page",
  fallback: true, // process.env.NODE_ENV === 'development',
  formatPath: ({ uid }) => ({ params: { 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.