Day 11: Bootstrap 4 Navigation Tutorial and Examples

Hello and welcome to the 11th day of Bootstrap 4 😎 Today we will learn about the Bootstrap 4 Navigation options. Having to organise a list of links is a very common situation and knowing how to create Bootstrap 4 Navs will help you solve this.

There are multiple options you will be able to choose from: basic navs, nav tabs and nav pills. We will inspect each option and explain how to use it, together with examples. We will also start to see more of the JavaScript options Bootstrap 4 provides. Sounds exciting? Let’s learn to navigate!

bootstrap-4-navigation

Photo credit to Daryl Beaney for his shot.

The article is structured into the following parts:

Bootstrap 4 Navigation Basic Example

When you are organising a navigation menu inside your page, there are multiple options you can choose from. The first and the simplest one is to have a list of links leading to different parts of your page or other pages.

The basic container for the links should have the .nav class. You will need to use it together with the .nav-link class applied on link, and the .nav-item class applied on the container of the link. The element with the .nav class acts as a Bootstrap 4 flex container and using .nav-items you will be sure the elements align as expected.

Using the Bootstrap 4 classes, instead of the usual links offers multiple positive points: it adds padding to the links – for a larger hit area, it offers disabled styling and the flex utilities.

Here is a basic example of a list of links using the .nav class:

dark

<ul class="nav">
    <li class="nav-item">
      <a class="nav-link active" href="#">Falcon</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Parrot</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Owl</a>
    </li>
    <li class="nav-item">
      <a class="nav-link disabled" href="#">Stork</a>
    </li>
</ul>

Side Note: I will mainly use bird species and descriptions in the next examples. There are so many species I can easily choose from so they seemed like a good fit πŸ™‚

Navigation with Flex Utilities

Since the .nav element is a flex container, you can use the Bootstrap 4 flex classes to align the elements inside it. The default behaviour is for the elements to be placed on a row, starting from the left.

But you can also stack them vertically with the .flex-column class:

dark

<ul class="nav flex-column">
  <li class="nav-item">
    <a class="nav-link active" href="#">Vulture</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Hawk</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#">Woodpecker</a>
  </li>
</ul>

And you can align them on their first axis with the .justify-content-[position] class. Here is an example with the links pulled to the right with the .justify-content-end class:

dark

<ul class="nav justify-content-end">
  <li class="nav-item">
    <a class="nav-link active" href="#">Kingfisher</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Hornbill</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Cormorant</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#">Penguin</a>
  </li>
</ul>

And here is an example with the links centered with the .justify-content-center class:

dark

<ul class="nav justify-content-center">
  <li class="nav-item">
    <a class="nav-link active" href="#">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Albatross</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Pigeon</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#">Crane</a>
  </li>
</ul>

To see more flex capabilities, you can go back to Bootstrap 4 flex tutorial and refresh your memory.

Another option for navigation is to show and hide content depending on the link you select. Also known as tabbable regions, you can easily accomplish this with the Bootstrap 4 tab Javascript plugin. The plugin is included in the bootstrap.js file. You need to make sure you have it included. You can check Day 1: Bootstrap 4 CDN and Starter Template on instructions on how to do this.

There are two options to create tabbable content: the navigation tabs and the navigation pills. We will take them one by one.

Bootstrap 4 Navigation Tabs

Tabs are a set of links with a tabbed interface. To use them, you will need to also add the .nav-tabs class together with the .nav class. Here is the result:

dark

<ul class="nav nav-tabs">
  <li class="nav-item">
    <a class="nav-link active" href="#">Duck</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Chicken</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Kiwi</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#">Emu</a>
  </li>
</ul>

JavaScript Behaviour

To add the panels with content we need the place them in a container with the class .tab-content and give each panel the .tab-pane class. By default, their visibility is hidden. To show one of the tabs, you will need to add the class .active to it. There should be a correlation between the link that is active in the .nav-tabs list and the tab that is active in the .tab-content.

In our example, we will want to show the description for the Duck, since the Duck link is active:

dark

<ul class="nav nav-tabs">
...
</ul>
<div class="tab-content mt-3">
  <div class="tab-pane active" id="duck" role="tabpanel" aria-labelledby="duck-tab">...</div>
  <div class="tab-pane" id="chicken" role="tabpanel" aria-labelledby="chicken-tab">...</div>
  <div class="tab-pane" id="kiwi" role="tabpanel" aria-labelledby="kiwi-tab">...</div>
  <div class="tab-pane" id="emu" role="tabpanel" aria-labelledby="emu-tab">...</div>
</div>

The next step is to tie all the links in the .nav-tabs to the panels in the .tab-content. The behaviour we want is that when a link is pressed, the current panel gets hidden and the tab with the information associated with it is displayed. We ca do this in two ways: using data attributes or via JavaScript calls. We’ll have examples with both.

Using Data Attributes

You can make the links in the .nav-tabs toggle the panels without writing any JavaScript yourself. You will need to add the data attribute data-toggle=”tab” to the links and tell every link what is should display through its anchor.

We will do this with the example above:

dark

<ul class="nav nav-tabs" role="tablist">
  <li class="nav-item">
    <a class="nav-link active" data-toggle="tab" href="#duck" role="tab" aria-controls="duck" aria-selected="true">Duck</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#chicken" role="tab" aria-controls="chicken" aria-selected="false">Chicken</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#kiwi" role="tab" aria-controls="kiwi" aria-selected="false">Kiwi</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" data-toggle="tab" href="#emu" role="tab" aria-controls="emu" aria-selected="false">Emu</a>
  </li>
</ul>

<div class="tab-content mt-3">
  <div class="tab-pane active" id="duck" role="tabpanel" aria-labelledby="duck-tab">
    ...             
  </div>
  <div class="tab-pane" id="chicken" role="tabpanel" aria-labelledby="chicken-tab">
      ...
  </div>
  <div class="tab-pane" id="kiwi" role="tabpanel" aria-labelledby="kiwi-tab">
      ...          
  </div>
  <div class="tab-pane" id="emu" role="tabpanel" aria-labelledby="emu-tab">
    ...           
  </div>
</div>

Using JavaScript Calls

Another way to make the right panel appear when the link for it is pressed is to use JavaScript. This means you will not need the data-toggle="tab" attribute anymore. But you will need to keep the anchor to the corresponding panel.

dark

//html
<ul class="nav nav-tabs" id="birds" role="tablist">
  <li class="nav-item">
    <a class="nav-link active"  href="#duck" role="tab" aria-controls="duck" aria-selected="true">Duck</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#chicken" role="tab" aria-controls="chicken" aria-selected="false">Chicken</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#kiwi" role="tab" aria-controls="kiwi" aria-selected="false">Kiwi</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#emu" role="tab" aria-controls="emu" aria-selected="false">Emu</a>
  </li>
</ul>

<div class="tab-content mt-3">
  <div class="tab-pane active" id="duck" role="tabpanel" aria-labelledby="duck-tab">
    ...            
  </div>
  <div class="tab-pane" id="chicken" role="tabpanel" aria-labelledby="chicken-tab">
      ...
  </div>
  <div class="tab-pane" id="kiwi" role="tabpanel" aria-labelledby="kiwi-tab">
    ...          
  </div>
  <div class="tab-pane" id="emu" role="tabpanel" aria-labelledby="emu-tab">
    ...            
  </div>
</div>
        
//js
$('#birds a').on('click', function (e) {
  e.preventDefault()
  $(this).tab('show')
})

If your use-case for the tabs is what we illustrated before, then using data attributes is easier and I would recommend that. But if you want other events along happening on tab show, then it is better to use the JavaScript method because it offers more possibilities. We will explain them in the Bootstrap 4 navigation advanced Javascript behaviour part.

Fill and Justify

There are 2 classes for styling the Bootstrap 4 navigation tabs that may help you. If you want the tabs in the .nav-tabs to take out the entire width of its parent you can use the .nav-fill class and the space will be divided between the tabs according to their width.

dark

<ul class="nav nav-tabs nav-fill" role="tablist">
    ...
</ul>

<div class="tab-content">
    ...
</div>

Or you can use the .nav-justified class if you want every tab to have the same width.

dark

<ul class="nav nav-tabs nav-justified" role="tablist">
    ...
</ul>

<div class="tab-content">
    ...
</div>

Flex Utilities

You can get the behaviour described above by using the .flex-fill and and .flex-grow classes that we learnt in the Bootstrap 4 flex tutorial.

Since the .nav is a flexbox container, you can use any of the Bootstrap 4 flex utilities and responsive breakpoints. This will give you more power over how the items get aligned. Here is an example of a tab that gets pulled to the right:

dark

<ul class="nav nav-tabs" role="tablist">
  <li class="nav-item">
    <a class="nav-link active" data-toggle="tab" href="#duck" role="tab" aria-controls="duck" aria-selected="true">Duck</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#chicken" role="tab" aria-controls="chicken" aria-selected="false">Chicken</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="tab" href="#kiwi" role="tab" aria-controls="kiwi" aria-selected="false">Kiwi</a>
  </li>
  <li class="nav-item ml-auto">
    <a class="nav-link disabled" data-toggle="tab" href="#emu" role="tab" aria-controls="emu" aria-selected="false">Emu</a>
  </li>
</ul>

<div class="tab-content mt-3">
  <div class="tab-pane active" id="duck" role="tabpanel" aria-labelledby="duck-tab">
      ...
  </div>
  <div class="tab-pane" id="chicken" role="tabpanel" aria-labelledby="chicken-tab">
      ...
  </div>
  <div class="tab-pane" id="kiwi" role="tabpanel" aria-labelledby="kiwi-tab">
    ...          
  </div>
  <div class="tab-pane" id="emu" role="tabpanel" aria-labelledby="emu-tab">
    ...           
  </div>
</div>

Bootstrap 4 Navigation Pills

To change the styling of the navigation to pills, you will need to use the .nav-pills class:

dark

<ul class="nav nav-pills">
  <li class="nav-item">
    <a class="nav-link active" href="#">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Ostrich</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" href="#">Tropicbird</a>
  </li>
</ul>

Just like with tabs, you will need to have the content of the panels that get toggled inside a .tab-content parent. And each panel will need the .tab-panel class, making use one also has the .active class so it gets displayed:

dark

<ul class="nav nav-pills">
    <li class="nav-item">
    <a class="nav-link active" href="#">Flamingo</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="#">Cuckoo</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="#">Ostrich</a>
    </li>
    <li class="nav-item">
    <a class="nav-link disabled" href="#">Tropicbird</a>
    </li>
</ul>
<div class="tab-content mt-3">
    <div class="tab-pane active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
      ...
    </div>
    <div class="tab-pane" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
      ...
    </div>
    <div class="tab-pane" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
      ...
    </div>
    <div class="tab-pane" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
      ...
    </div>
</div>

JavaScript Behaviour

In order to toggle the panels when you press on a pill, you have two options. You can use data attributes or JavaScript calls. They are the same ones listed for the nav tabs.

Using Data Attributes

You can use data attributes and by adding data-toggle="pill" on every link in the navigation bar and the anchor to its panel:

dark

<ul class="nav nav-pills">
  <li class="nav-item">
    <a class="nav-link active" data-toggle="pill" href="#flamingo" role="tab" aria-controls="pills-flamingo" aria-selected="true">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="pill" href="#cuckoo" role="tab" aria-controls="pills-cuckoo" aria-selected="false">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="pill" href="#ostrich" role="tab" aria-controls="pills-ostrich" aria-selected="false">Ostrich</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" data-toggle="pill" href="#tropicbird" role="tab" aria-controls="pills-tropicbird" aria-selected="false">Tropicbird</a>
  </li>
</ul>
<div class="tab-content mt-3">
  <div class="tab-pane active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
    ...
  </div>
  <div class="tab-pane" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
    ...
  </div>
  <div class="tab-pane" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
    ...
  </div>
  <div class="tab-pane" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
    ... 
  </div>
</div>

Using JavaScript Calls

Or you can use a JavaScript function that calls the .tab('show') function each time a link gets pressed:

dark

//html 
<ul class="nav nav-pills" id="birds">
  <li class="nav-item">
    <a class="nav-link active" href="#flamingo" role="tab" aria-controls="pills-flamingo" aria-selected="true">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#cuckoo" role="tab" aria-controls="pills-cuckoo" aria-selected="false">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#ostrich" role="tab" aria-controls="pills-ostrich" aria-selected="false">Ostrich</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled"  href="#tropicbird" role="tab" aria-controls="pills-tropicbird" aria-selected="false">Tropicbird</a>
  </li>
</ul>
<div class="tab-content mt-3">
  <div class="tab-pane active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
    ...
  </div>
  <div class="tab-pane" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
    ...
  </div>
  <div class="tab-pane" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
    ...
  </div>
  <div class="tab-pane" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
    ... 
  </div>
</div>  

//js
$('#birds a').on('click', function (e) {
  e.preventDefault()
  $(this).tab('show')
})

Fill and Justify

Just like with the nav tabs, you can use the .nav-fill and .nav-justify class if you want the list of pills to take the entire width of their parent.

Here is how the .nav-fill looks:

dark

<ul class="nav nav-pills nav-fill">
    ...
</ul>
<div class="tab-content mt-3">
    ...
</div>

And here is how the .nav-justified looks:

dark

<ul class="nav nav-pills nav-justified">
    ...
</ul>
<div class="tab-content mt-3">
    ...
</div>

Flex Utilities

And since the .nav is a Bootstrap 4 flex container, you can take advantage of the multiple classes it offers. We have created an example that shows how you can place the pills vertically on mobile and horizontally on devices starting with the tablet.

dark

<ul class="nav nav-pills flex-column flex-md-row text-center">
  <li class="nav-item">
    <a class="nav-link active" data-toggle="pill" href="#flamingo" role="tab" aria-controls="pills-flamingo" aria-selected="true">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="pill" href="#cuckoo" role="tab" aria-controls="pills-cuckoo" aria-selected="false">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" data-toggle="pill" href="#ostrich" role="tab" aria-controls="pills-ostrich" aria-selected="false">Ostrich</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled" data-toggle="pill" href="#tropicbird" role="tab" aria-controls="pills-tropicbird" aria-selected="false">Tropicbird</a>
  </li>
</ul>
<div class="tab-content mt-3">
    ...
</div>

Advanced JavaScript Behaviour

Fade Effect

You can make the panels fade in when the appear if you add the .fade class to each .tab-pane. The one that is active on page load will also need the .show class to be visible.

dark

<ul class="nav nav-pills">
    ...
</ul>
<div class="tab-content mt-3">
    <div class="tab-pane fade show active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
      ...
    </div>
    <div class="tab-pane fade" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
     ...
    </div>
    <div class="tab-pane fade" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
      ...
    </div>
    <div class="tab-pane fade" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
      ... 
    </div>
</div>

Methods

.tab(β€˜show’)

When you call the .tab('show') method for a link in the .nav the link will become active and the panel for it will become visible. In the example above we were calling the .tab('show') on the click event for every link in the .nav (that is the standard behaviour). But we can call the method in other functions too. For example, here is a button that opens the second tab in a navbar when clicked:

dark

//html
<ul class="nav nav-pills" id="birds">
  <li class="nav-item">
    <a class="nav-link active" href="#flamingo" role="tab" aria-controls="pills-flamingo" aria-selected="true">Flamingo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link"  id="cuckoo-pill" href="#cuckoo" role="tab" aria-controls="pills-cuckoo" aria-selected="false">Cuckoo</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#ostrich" role="tab" aria-controls="pills-ostrich" aria-selected="false">Ostrich</a>
  </li>
  <li class="nav-item">
    <a class="nav-link disabled"  href="#tropicbird" role="tab" aria-controls="pills-tropicbird" aria-selected="false">Tropicbird</a>
  </li>
</ul>
<div class="tab-content mt-3">
    <div class="tab-pane active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
      ...
    </div>
    <div class="tab-pane" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
      ...
    </div>
    <div class="tab-pane" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
      ...
    </div>
    <div class="tab-pane" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
      ...
    </div>
</div>   

<button type="button" class="btn btn-success btn-sm mt-3" id="show-cuckoo">Show cuckoo</button>

//js
$('#birds a').on('click', function (e) {
  e.preventDefault();
  $(this).tab('show');
})

$('#show-cuckoo').on('click', function () {
  $('#cuckoo-pill').tab('show');
})

Events

When changing tabs, there are a series of events that take place. We will take each event and describe its behaviour and the order in comes in.

Order Event Target Description
1 hide.bs.tab the current active tab This event fires when a new tab is to be shown (and thus the previous active tab is to be hidden). Use event.targetand event.relatedTargetto target the current active tab and the new soon-to-be-active tab, respectively.
2 show.bs.tab the to-be-shown tab This event fires on tab show, but before the new tab has been shown. Use event.targetand event.relatedTargetto target the active tab and the previous active tab (if available) respectively.
3 hidden.bs.tab on the previous active tab, the same one as for the hide.bs.tabevent This event fires after a new tab is shown (and thus the previous active tab is hidden). Use event.targetand event.relatedTargetto target the previous active tab and the new active tab, respectively.
4 shown.bs.tab on the newly-active just-shown tab, the same one as for the show.bs.tabevent This event fires on tab show after a tab has been shown. Use event.targetand event.relatedTargetto target the active tab and the previous active tab (if available) respectively.

If you don’t have a tab that is already active, then the hide.bs.tab and hidden.bs.tab events will not be triggered.

To see how you can use the events, we have created an example that modifies the color of the nav pills that have been visited to light blue. When the shown event gets triggered we make the relatedTarget (which is the tab that gets hidden) get the .light-blue class which modifies the background color.

dark

//html
<ul class="nav nav-pills">
    ...
</ul>
<div class="tab-content mt-3">
    <div class="tab-pane active" id="flamingo" role="tabpanel" aria-labelledby="flamingo-tab">
      ...
    </div>
    <div class="tab-pane" id="cuckoo" role="tabpanel" aria-labelledby="profile-tab">
      ...
    </div>
    <div class="tab-pane" id="ostrich" role="tabpanel" aria-labelledby="ostrich-tab">
      ...
    </div>
    <div class="tab-pane" id="tropicbird" role="tabpanel" aria-labelledby="tropicbird-tab">
      ... 
    </div>
</div> 

//js
$('a[data-toggle="pill"]').on('shown.bs.tab', function (e) {
  $(e.target).removeClass( "light-blue" );
  $(e.relatedTarget).addClass( "light-blue" );
})

That is all for today! You can see and edit all the code used in this article on Codepen. Let me know if you run into difficulties when trying to create your navigation. Have a nice evening and make sure to celebrate your progress!

bootstrap-4-navigation-end

Photo credit to Kyle Letendre for his shot.

Further Reading

If you have more time, here are some useful resources:

Photo credit to Yuliya for her shot.

Sharing is caring!

Cristina Conacel

Cristina is a web developer and the owner of BootstrapBay. She likes foxes, clean design, writing blog posts and creating themes that are useful to other developers.