Strapi Navigation Menu using Components with Next.js and GraphQL
Menus of websites can be super boring links. Or also very boring drop downs with some more links. But menus can also be much more. They can be very engaging and user friendly.
Watch the Video
We need your consent
This content is provided by YouTube. If you activate the content, personal data may be processed and cookies may be set.
Examples of Engaging Menus
For example the menu of the website from Strapi you have a nice, engaging menu that is much more than just a few links. There is a lot going on. A link consists of an icon and a description text, which makes it way easier to understand what I can expect from the linked page.
There is also some page preview with a large image and link button.
Another nice example is the fly out menu from the Tailwind components. It as well has a link list with icons and showing two page previews side by side.
Our Example Menu
The goal for this post is to look into the basics on how you can implement a menu like the ones above yourself. Using Strapi as a headless CMS the menus of course should be configurable from within Strapi, so content editors will be empowered to change those themselves.
To achieve this we will create a menu that is using Strapi components. In the end it will look something like this:
The Structure of a Menu
As you can see in the example above we want to have two menu items. On is called "Home" and is just a simple link.
But the second one called "Content" has a dropdown. Inside of the dropdown we will render different components.
The first component is a link list. It contains multiple links where each link has an icon, title and description text. Of course also an href.
The second component is a page preview component. This is a component that references another page. And from that referenced page it pulls that data for title, synopsis and the preview image.
Also we want to be able to create multiple menus, not just one. So a menu will be a collection type. Menu items will also be a collection types and a relation inside the menu. A menu item then is either a simple link with a label and an href or it has a dynamic zone so we can add components. In case it has components in the dynamic zone configured in Strapi we will render the dropdown.
So on a high level concept it looks like this:
Strapi Configuration for the Menu
Let's look into the Strapi component types, menu and menu item.
Fetching the Menu Data using GraphQL
Once you created an actual menu and added some menu items, we need to fetch the data in our Next.js frontend.
We will be using GraphQL for data fetching.
I use one query that fetches all global website data, which also includes the main menu. In a simplistic version it looks like this:
We are querying menus by its name "main" since it is named like this in the Strapi backend. For the actual data I use a GraphQL fragment. Fragments lets me structure the queries much better. Also it allows me to reuse fragments, for example for components that can be used in different places.
The fragments for the menu, menu items and components look like this:
This data is fetched using graphql-request in a react server component in Next.js. This way the data fetching and the rendering happens on the server side. Still the output of the website is cached and therefor very fast.
I like the simple graphql library since for mostly non interactive content pages I like to not have those crazy complicated caching mechanisms of client side focussed graphql libraries like apollo.
The query documents that are being used for the request are automatically generated using graphql-codegen.
With that the request looks as simple as this:
React Components for the Menu
Once the data is fetched you can use it in a menu component. For the menu I am using a Popover from headless ui.
The main parts of the menu are the Menu and MenuItem component. And another implementation for the mobile version of the menu, but let's focus on the desktop one.
The main idea is that you map through the MenuItem relations of a Menu. Then within a menu item you would check if it is just a link or contains components. If there are components you would use the Popover and then use a ComponentRenderer to render the components of the Strapi dynamic zone.
The ComponentRenderer is a React component that takes a map to know for what Strapi component which React component should be used. I always have a default componentMap that is used when the ComponentRenderer is used on normal content pages. But for the MenuItem I alter the configuration of the map a bit. Because in the MenuItem some Strapi components should be rendered differently than on normal content pages.
This is how it looks like in code:
And that's all the parts you need to create configurable and engaging menus with Strapi and Next.js.