Navigation Menus
Whether your website has thousands of pages or just one, it likely needs lists of links for navigation. This guide describes a simple and scalable way to manage navigation menus within Prismic.
The content models you’ll build throughout this guide support the following key features:
- All navigation menus can be managed in Prismic. Content managers will be able to add, edit, and remove links from the menus.
- Navigation menus can be reused in multiple contexts. A list of links displayed in the header, for example, could be reused in the footer with different styling.
- Top-level links can contain child links when needed. Organizing pages under a parent is a common strategy to simplify top-level navigation menus.
- Links can go anywhere. Content managers can link to whatever they need, both within the Prismic repository or out to other sites.
🏃♀️ Want to see the final result in action?
Create a new Prismic project with everything described in this guide with the following commands:
npx degit prismicio-community/how-to-nextjs-navigation how-to-nextjs-navigation
cd how-to-nextjs-navigation
npx @slicemachine/init
The reusable Navigation Item Slice represents navigation links and their optional child links. It will be attached to the Navigation custom type.
Recreate the following Navigation Item in Slice Machine:
- NamenameName of the linkRich Text
- LinklinkLink for the itemLink
- Child Namechild_nameName of the child linkRich Text
- Child Linkchild_linkLink for the child itemLink
Copy{
"id": "navigation_item",
"type": "SharedSlice",
"name": "NavigationItem",
"description": "NavigationItem",
"variations": [
{
"id": "default",
"name": "Default",
"docURL": "...",
"version": "sktwi1xtmkfgx8626",
"description": "NavigationItem",
"primary": {
"name": {
"type": "StructuredText",
"config": {
"label": "Name",
"placeholder": "Name of the link",
"allowTargetBlank": false,
"single": "heading3"
}
},
"link": {
"type": "Link",
"config": {
"label": "Link",
"placeholder": "Link for the item",
"allowTargetBlank": true,
"select": null
}
}
},
"items": {
"child_name": {
"type": "StructuredText",
"config": {
"label": "Child Name",
"placeholder": "Name of the child link",
"allowTargetBlank": false,
"single": "heading6"
}
},
"child_link": {
"type": "Link",
"config": {
"label": "Child Link",
"placeholder": "Link for the child item",
"allowTargetBlank": true,
"select": null
}
}
},
"imageUrl": "https://images.prismic.io/slice-machine/621a5ec4-0387-4bc5-9860-2dd46cbc07cd_default_ss.png?auto=compress,format"
}
]
}
The Navigation custom type represents collections of links, such as a website’s header or footer navigation. It uses the Navigation Item Slice created above.
Recreate the following Navigation custom type in Slice Machine as a Reuseable custom type:
- NamenameName of the navigation listRich Text
- UIDuidUnique ID for the navigation listUID
- NavigationItemSlice
Copy{
"id": "navigation",
"label": "Navigation",
"repeatable": true,
"status": true,
"json": {
"Main": {
"name": {
"type": "StructuredText",
"config": {
"label": "Name",
"placeholder": "Name of the navigation list",
"allowTargetBlank": false,
"single": "heading1"
}
},
"uid": {
"type": "UID",
"config": {
"label": "UID",
"placeholder": "Unique ID for the navigation list"
}
},
"slices": {
"type": "Slices",
"fieldset": "Slice Zone",
"config": {
"choices": {
"navigation_item": {
"type": "SharedSlice"
}
}
}
}
}
}
}
Open Prismic and create a Navigation Menu document with content.
Navigation documents can be queried in a Next.js page’s getStaticProps()
function. The document’s data can be used directly in the page or forwarded to a custom reusable component, like a <Layout>
or <Navigation>
component.
export async function Page({ navigation, page }) {
// The `navigation` document can be used here.
}
export async function getStaticProps({ params, previewData }) {
const client = createClient({ previewData })
const [navigation, page] = await Promise.all([
client.getByUID('navigation', 'header'),
client.getByUID('page', params.uid),
])
return {
props: {
navigation,
page,
},
}
}
Learn more about querying in the Fetch Data article.
The navigation menu data returned from Prismic contains an array of Slices holding your links.
The following <Navigation>
component is one way to loop through each link and render it. You can customize the component by adding your own styling.
It makes use of @prismicio/react
's <PrismicLink>
component which requires Next.js-specific set up. See the Set up Prismic article for details.
import { PrismicLink, PrismicText } from '@prismicio/react'
export function Navigation({ navigation }) {
return (
<nav>
<ul>
{/* Renders top-level links. */}
{navigation.data.slices.map((slice) => {
return (
<li key={slice.id}>
<PrismicLink field={slice.primary.link}>
<PrismicText field={slice.primary.name} />
</PrismicLink>
{/* Renders child links, if present. */}
{slice.items.length > 0 && (
<ul>
{slice.items.map((item) => {
return (
<li key={JSON.stringify(item)}>
<PrismicLink field={item.child_link}>
<PrismicText field={item.child_name} />
</PrismicLink>
</li>
)
})}
</ul>
)}
</li>
)
})}
</ul>
</nav>
)
}
The <Navigation>
component can be used on a page like so:
import { Navigation } from '../components/Navigation'
export async function Page({ navigation, page }) {
return (
<div>
<Navigation navigation={navigation} />
{/* The rest of your component... */}
</div>
)
}
export async function getStaticProps({ params, previewData }) {
const client = createClient({ previewData })
const [navigation, page] = await Promise.all([
client.getByUID('navigation', 'header'),
client.getByUID('page', params.uid),
])
return {
props: {
navigation,
page,
},
}
}
Learn more about templating content in the Template Content article.
The navigation strategy shared in this article can be used as-is or as a base for your own custom navigation strategy.
Here are a few ideas you can try to customize your navigation menus:
- Allow content managers to select an icon for each link and display them in the menu.
- Support short descriptions for top-level navigation items.
- Automatically display an “external link” icon next to links pointing to external websites.
- If you don’t need child links, remove the Repeatable Zone fields from the NavigationItem Slice and remove its accompanying React code.
Was this article helpful?
Can't find what you're looking for? Spot an error in the documentation? Get in touch with us on our Community Forum or using the feedback form above.