Skip to main content

How to create a responsive navbar

January 30, 2024About 4 min

How to create a responsive navbar

  • At the moment our navbar is not responsive
  • Right now we should have enough Angular and Tailwind knowledge to make the navbar responsive

The idea

  • The idea is to create a navbar that shows all the navigation links on medium screen and bigger
  • On a device smaller than medium we want to show the hamburger icon instead of the links
    • Clicking on the hamburger icon toggles a list of the navigation links one below each other

The process

  • We'll create our responsive navbar in the menu.component.html
  • First remove all the CSS in the menu.component.css!!!
  • We start with the surrounding semantic nav-tag
  • We're giving it a white background, a gray border and some padding
<nav class="bg-white border-gray-200 px-2 sm:px-4 py-2.5">
</nav>

div container

  • Inside the nav we define a div container, which is a flexbox containing
    • The title
    • The hamburger icon (button) = hidden on medium screens and larger
    • Another div which contains the ul, the actual list of navigation links
  • flex-wrap: wraps the item to a new row if there is not enough space
  • justify-between creates an equal space between all items (main axis) = horizontally
  • items-center aligns the items along the center of the container's cross axis = vertically
<nav class="bg-white border-gray-200 px-2 sm:px-4 py-2.5">
    <div class="container flex flex-wrap justify-between items-center mx-auto">
    </div>
</nav>

 
 

Title

  • The link that contains the title is also a flexbox container
  • The child items are aligned along the center of the container's cross axis = vertically
  • The span also aligns itself along the center of the container's cross axis = vertically
<nav class="bg-white border-gray-200 px-2 sm:px-4 py-2.5">
    <div class="container flex flex-wrap justify-between items-center mx-auto">
        <a href="#" class="flex items-center">
            <span class="self-center text-xl font-semibold">My News</span>
        </a>
    </div>
</nav>


 
 
 


Hamburger icon (button)

  • The button has several Tailwind classes
    • inline-flex: creates an inline flex container that flows with text
    • Center the span & svg (across the main axis)
    • focus:ring-2 surrounds the element with a ring on focus
    • rounded-lg: the button is rounded with a 'large' radius
    • md-hidden: the button is hidden if medium screen or larger
  • The span is used for the screen readers. The text is not visible but will be read by screen readers on focus = sr-only
  • The svg and path are just the three lines to create the hamburger icon
<nav class="bg-white border-gray-200 px-2 sm:px-4 py-2.5">
    <div class="container flex flex-wrap justify-between items-center mx-auto">
        <a href="#" class="flex items-center">
            <span class="self-center text-xl font-semibold">My News</span>
        </a>
      <button (click)="toggleHamburger()" data-collapse-toggle="navbar-default" type="button"
              class="inline-flex items-center p-2 ml-3 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200"
              aria-controls="navbar-default" aria-expanded="false">
        <span class="sr-only">Open main menu</span>
        <svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20"
             xmlns="http://www.w3.org/2000/svg">
          <path fill-rule="evenodd"
                d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
                clip-rule="evenodd"></path>
        </svg>
      </button>
    </div>
</nav>





 
 
 
 
 
 
 
 
 
 
 


  • Last but not least we add a div and a ul within this div which contains the navigation links
  • The div:
    • w-full: the div takes all the available width (100%)
    • md-block: medium and larger screens: the div is shown and acts like a block level element
    • md:w-auto: medium and larger screens: the width is automatically determined
    • [hidden]="!hamburgerOpen": based on if we clicked the hamburger icon yes/no the div is shown/hidden
      • The boolean hamburgerOpen is set in the component class
  • The ul:
    • flex flex-col: items are organised one below each other in a flex way
    • md:flex-row: medium and larger screens: items are organised in a row, next to each other
    • md:space-x-8: medium and larger screens: create some horizontal space between the items
<nav class="bg-white border-gray-200 px-2 sm:px-4 py-2.5">
  <div class="container flex flex-wrap justify-between items-center mx-auto">
    <a href="#" class="flex items-center">
      <span class="self-center text-xl font-semibold">My News</span>
    </a>
    <button (click)="toggleHamburger()" data-collapse-toggle="navbar-default" type="button"
            class="inline-flex items-center p-2 ml-3 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200"
            aria-controls="navbar-default" aria-expanded="false">
      <span class="sr-only">Open main menu</span>
      <svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20"
           xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd"
              d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
              clip-rule="evenodd"></path>
      </svg>
    </button>
    <div class="w-full md:block md:w-auto" id="navbar-default" [hidden]="!hamburgerOpen">
      <ul
              class="flex flex-col p-4 mt-4 bg-gray-50 rounded-lg border border-gray-100 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium md:border-0 md:bg-white ">
        <li>
          <a (click)="onHamburgerItemClick()" routerLink="/" routerLinkActive="active"
             [routerLinkActiveOptions]="{ exact: true }" class="block py-2 pr-4 pl-3 rounded ">Home</a>
        </li>
        <li>
          <a (click)="onHamburgerItemClick()" routerLink="/article" routerLinkActive="active"
             [routerLinkActiveOptions]="{ exact: true }" class="block py-2 pr-4 pl-3 rounded">Article</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
















 
 
 
 
 
 
 
 
 
 
 
 
 


  • The code of the MenuComponent class:
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Router } from '@angular/router';

@Component({
  selector: 'app-menu',
  standalone: true,
  imports: [CommonModule, RouterModule],
  templateUrl: './menu.component.html',
  styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit(): void {
  }

  hamburgerOpen = false;

  toggleHamburger(): void {
    this.hamburgerOpen = !this.hamburgerOpen;
  }

  onHamburgerItemClick() {
    if (this.hamburgerOpen) {
      this.hamburgerOpen = false;
    }
  }

  navigateTo(path: string) {
    this.hamburgerOpen = false;
    this.router.navigate([path]);
  }
}

Active item

  • We need a little more css code to show which navigation link is active
  • Go to menu.component.css and add the following lines:
nav a.active {
    background-color: lightsalmon;
    color: black;
} 

Result

  • Medium+ screen:
    • navbar medium
      navbar medium
  • Small screen:
    • navbar small
      navbar small
    • navbar small expanded
      navbar small expanded