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:
- LinklinkLink for the itemLink
- 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": {
"link": {
"type": "Link",
"config": {
"label": "Link",
"placeholder": "Link for the item",
"allowTargetBlank": true,
"select": null,
"allowText": true
}
}
},
"items": {
"child_link": {
"type": "Link",
"config": {
"label": "Child Link",
"placeholder": "Link for the child item",
"allowTargetBlank": true,
"select": null,
"allowText": true
}
}
},
"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 layout file and called using the RootLayout
function. This way, it's only queried once and added to all the pages above or below the page content.
The data is queried within the <Navigation>
component using the getByUID function. UPDATE THE UID TO MATCH YOURS. 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/next
's <PrismicNextLink>
component.
- Full File
- Navigation component
- RootLayout
import { PrismicNextLink, PrismicPreview } from "@prismicio/next";
import { createClient, repositoryName } from "@/prismicio";
export default async function RootLayout({ children }) {
return (
<html lang="en">
<body className="overflow-x-hidden antialiased">
{/* @ts-expect-error Async Server Component */}
<Navigation />
{children}
<PrismicPreview repositoryName={repositoryName} />
</body>
</html>
);
}
async function Navigation() {
const client = createClient();
const navigation = await client.getByUID("navigation", "header-menu");
return (
<nav>
<ul>
{/* Renders top-level links */}
{navigation.data.slices.map((slice) => (
<li key={slice.id}>
<PrismicNextLink field={slice.primary.link} />
{/* Renders child links, if present */}
{slice.items.length > 0 && (
<ul>
{slice.items.map((item) => (
<li key={JSON.stringify(item)}>
<PrismicNextLink field={item.child_link} />
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
);
}
async function Navigation() {
const client = createClient();
const navigation = await client.getSingle("navigation");
return (
<nav>
<ul>
{/* Renders top-level links */}
{navigation.data.slices.map((slice) => (
<li key={slice.id}>
<PrismicNextLink field={slice.primary.link} />
{/* Renders child links, if present */}
{slice.items.length > 0 && (
<ul>
{slice.items.map((item) => (
<li key={JSON.stringify(item)}>
<PrismicNextLink field={item.child_link} />
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
);
}
export default async function RootLayout({ children }) {
return (
<html lang="en">
<body className="overflow-x-hidden antialiased">
{/* @ts-expect-error Async Server Component */}
<Navigation/>
{children}
<PrismicPreview repositoryName={repositoryName} />
</body>
</html>
);
}
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.
- Learn more about querying in the Fetch Data article.
- Learn more about templating content in the Template Content article.
Can't find what you're looking for?
Need technical Support? Spot an error in the documentation? Get in touch with us on our Community Forum.