How to customise child pages in Statamic's navigation

Ever wanted to build a megamenu style interface, or have child links appear differently to the top level? Here's how to do it.

Published July 28th 2019

Statamic’s {{ nav }} tag provides a relatively straight forward way to output a menu. However, the example in the documentation doesn’t provide a huge amount of control over the appearance of child pages.

While calling the menu recursively is a way of keeping the code simple, if you need more flexibility – e.g. as part of building a mega-menu style interface – it doesn’t really cut the mustard.

Fortunately, there’s a relatively simple way of gaining more control over how child menu items are displayed.

In the default example, child items are called like:

{{ if children }}
    <ul>{{ *recursive children* }}</ul>
{{ endif }}

As I mentioned before, this example relies on the concept of recursively looping through the menu using the structure defined before it. However, let’s say you want to split the child menu into two halves – one with an image and call to action, and the other with the menu items.

You’ll want the dropdown menu to have markup similar to below:

{{ if children }}
    <ul class="flex">
        <li class="w-1/2 bg-cover bg-no-repeat bg-center">
            <h3>Submenu title</h3>
            <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit.</p>
        <li class="w-1/2">
                {{ children }}
                        <a href="{{ url }}">{{ title }}</a>
                {{ /children }}
{{ endif }}

The key is the use of the {{ children }} tags, instead of {{ *recursive children* }}. This simple change will give you a lot more flexibility with how child elements are displayed within your {{ nav }} tags. Instead of having to rely on defining conditional logic at the top level, you can instead provide more detail.

You could even break it down into a partial and pass in the data for that section to keep your code lean, easy to read, and help Statamic parse more efficiently.

Styling based on depth

Update: August 2019. Jack McDade has revealed that it is possible to hook into the `depth` value on the child element, making it possible to style menus based on the level that they are into the loop using the following check.

{{ if depth == 2 }}

In the meantime, if there’s anything that isn’t clear, let me know on Twitter and I’ll add some more examples.