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.
Submitted by Bryan Garrant on 9th February, 2018