Fully Dynamic Hierarchical Nav Menu Template
Problem
You want to output a navigation menu that automatically lists a Structure Section’s page hierarchy, with various CSS classes that indicate current page, current section, has children, etc.
Solution
The Craft docs have a basic example of a hierarchical nav menu, but usually you want to add various CSS classes that indicate certain things about each page in the menu so you can style them appropriately. Here is a template that shows you how to add such classes.
<ul class="nav-list nav-list--level-1">
    {% set homeIsCurrent = (entry.section.handle == 'homepage') %}
    <li class="nav-item nav-item--home nav-item--level-1 {% if homeIsCurrent %}nav-item--current{% endif %}">
        <a href="{{ siteUrl }}">Home</a>
    </li>
    
    {% nav page in craft.entries.section('pages') %}
        {% set pageIsCurrent = (page.id == entry.id) %}
        {% set pageIsTopParent = (craft.request.firstSegment == page.uri) %}
        {% set pageIsInPath = (entry.uri matches '{^' ~ page.uri ~ '}') %}
        
        {% set classes = ['nav-item--level-' ~ page.level] %}
        {% set classes = classes|merge([pageIsCurrent ? 'nav-item--is-current' : '']) %}
        {% set classes = classes|merge([pageIsTopParent ? 'nav-item--is-top-parent' : '']) %}
        {% set classes = classes|merge([pageIsInPath ? 'nav-item--is-in-path' : '']) %}
        {% set classes = classes|merge([page.hasDescendants ? 'nav-item--has-children' : '']) %}
        {% set classes = classes|join(' ') %}
        <li class="{{ classes }}">
            <a href="{{ page.url }}">
                {{ page.title }}
                {% if page.hasDescendants %}<span class="nav-toggle nav-toggle--level-{{ page.level }}">▼</span>{% endif %}
            </a>
            {% ifchildren %}
                <ul class="nav-list nav-list--level-{{ page.level + 1 }}">
                    {% children %}
                </ul>
            {% endifchildren %}
        </li>
    {% endnav %}
</ul>Some things to note:
- Make sure you replace the ‘pages’ argument in craft.entries.section('pages')with the handle of your own structure section.
- You can of course set whatever CSS classes you want, but I am using nav-list,nav-itemprefixes to denote theulandlielements.
- You can change the actual CSS class names that get output, by altering the strings in the various {% set classes = ... %}lines.
- pageIsCurrentmeans that the nav item is the page currently being viewed.
- pageIsTopParentmeans that the nav item is a top-level page in the given section that is “above” the page currently being viewed (that is, it is the top-level menu item that the currently-viewed page lives under).
- pageIsInPathmeans that the nav item is a parent at any level (direct parent, grandparent, great-grandparent, etc.) of the page currently being viewed. Note that it will also be true for the page currently being viewed itself.
- All that “set classes” junk is kind of ugly, but it does keep a lot of logic out of the html itself, so in my opinion it is slightly cleaner than littering the actual css attribute of the html tags with a bunch of twig ifstatements.
- If you don’t want the homepage link in your nav menu, just delete that first <li>for it (along with theisHomevariable setting line above it).
Submitted by Jordan Lev on 1st February, 2017