Multi-level Bootstrap 4 Navbar With Craft 3 (No Plugins)

Problem

You want to setup a Bootstrap 4 Navbar and use native functions in Craft 3 to manage the navigation menu.

Solution

This was built for Bootstrap v4.0 and Craft CMS 3.0.0-RC9

Step 1: Install Craft 3

Go to https://github.com/craftcms/docs/blob/v3/en/installation.md and install Craft 3.

Step 2: Download and Install latest Bootstrap 4 build

Currently v4.0 which you can get at https://getbootstrap.com.

Step 3: Build Navigation in Craft 3 using a Structure 2 Level Section

Setup your 2 level Structure section for navigation in Craft 3. Call the section Navigation so the handle is navigation.

Setup four fields as follows:

Name: Link to a Site Asset

  • Handle: siteAssetLink
  • Instructions: Use this link type to link to any uploaded Asset on your site (PDFs, documents, images, etc.)
  • Field Type: Assets
  • Sources: All
  • Limit: 1

Name: Link to a Site Page

  • Handle: sitePageLink
  • Instructions: Use this link type to link to any other Page or Entry on your site
  • Field Type: Entries
  • Sources: All
  • Limit: 1
  • Selection Label: Add a Page

Name: Offsite Link

  • Handle: offsiteLink
  • Instructions: Use this link type to link to any URL outside of your website. Enter the full URL you would like to link * to including the http://
  • Field Type: URL

Name: Open In New Window

  • Handle: openInNewWindow
  • Instructions: Toggle this switch to Open this Link in a new browser tab or window
  • Field Type: Lightswitch
  • Default Value: off

Setup three Entry Types as follows in your Navigation Structure section:

Name: Internal Site Link

  • Handle: internalSiteLink
  • Show the Title Field: checked
  • Title Field Label: Title
  • Fields: Link to a Site Page

Name: Internal Asset Link

  • Handle: internalAssetLink
  • Show the Title Field: checked
  • Title Field Label: Title
  • Fields: Link to a Site Asset, Open in New Window

Name: Offsite Link

  • Handle: offsiteLink
  • Show the Title Field: checked
  • Title Field Label: Title
  • Fields: Offsite Link, Open in New Window

Step 4: Code it out

Setup your template code as follows:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="{{ siteUrl }}">{{ siteName }}</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarNavDropdown">

    {% set navigation = craft.entries.section('navigation') %}

    <ul class="navbar-nav mr-auto">
      {% nav node in navigation.level(1).all() %}
      {% if node.hasDescendants() %}

      <li class="nav-item dropdown">
        {% if node.type == 'internalSiteLink' %}
          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ node.id }}" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ node.title }}</a>
        {% elseif node.type == 'internalAssetLink' %}
          {% set asset = node.siteAssetLink.one() %}
          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ node.id }}" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ node.title }}</a>
        {% elseif node.type == 'offsiteLink' %}
          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ node.id }}" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ node.title }}</a>
        {% endif %}
        <div class="dropdown-menu" aria-labelledby="navbarDropdown{{ node.id }}">
          {% set nodeSubs = node.getChildren() %}
          {% for nodeSub in nodeSubs.all() %}
            {% if nodeSub.type == 'internalSiteLink' %}
              <a class="dropdown-item" href="{{ nodeSub.sitePageLink[0].url }}">{{ nodeSub.title }}</a>
            {% elseif nodeSub.type == 'internalAssetLink' %}
              {% set asset = nodeSub.siteAssetLink.one() %}
              <a class="dropdown-item" href="{{ asset.url }}" {% if nodeSub.openInNewWindow %} target="_blank" {% endif %}>{{ nodeSub.title }}</a>
            {% elseif node.type == 'offsiteLink' %}
              <a class="dropdown-item" href="{{ nodeSub.offsiteLink }}" {% if nodeSub.openInNewWindow %} target="_blank" {% endif %}>{{ nodeSub.title }}</a>
            {% endif %}
          {% endfor %}
        </div>
      </li>

      {% else %}

      <li class="nav-item">
        {% if node.type == 'internalSiteLink' %}
          <a class="nav-link" href="{{ node.sitePageLink[0].url }}">{{ node.title }}</a>
        {% elseif node.type == 'internalAssetLink' %}
          {% set asset = node.siteAssetLink.one() %}
          <a class="nav-link" href="{{ asset.url }}" {% if node.openInNewWindow %} target="_blank" {% endif %}>{{ node.title }}</a>
        {% elseif node.type == 'offsiteLink' %}
          <a class="nav-link" href="{{ node.offsiteLink }}" {% if node.openInNewWindow %} target="_blank" {% endif %}>{{ node.title }}</a>
        {% endif %}
      </li>

      {% endif %}
      {% endnav %}
    </ul>

  </div><!--/.navbar-collapse -->
</nav>

As new Bootstrap 4 and Craft 3 releases come out you may need to tweak the code. Just watch their changelogs for any changes.