Skip to main content

How to create a responsive navbar

About 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" [attr.aria-expanded]="hamburgerOpen">
            <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
    • [ngClass]="hamburgerOpen ? 'block' : 'hidden'": 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" [attr.aria-expanded]="hamburgerOpen">
            <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:w-auto md:block" id="navbar-default" [ngClass]="hamburgerOpen ? 'block' : 'hidden'">
            <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 { NgClass } from "@angular/common";
import { Component, inject } from "@angular/core";
import { Router, RouterModule } from "@angular/router";

@Component({
  selector: "app-menu-component",
  imports: [NgClass, RouterModule],
  templateUrl: "./menu-component.html",
  styleUrl: "./menu-component.css",
})
export class MenuComponent {
  private router = inject(Router);

  hamburgerOpen = false;

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

  onHamburgerItemClick() {
    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