I've built a lot of Angular admin dashboards over the years and the navbar is always where people get stuck. Either they can't get the mobile toggle working properly, the active route detection is broken, or they've wired up Bootstrap's JS in a way that fights Angular's change detection.

This guide shows you how to do it properly with Angular 21 standalone components and Bootstrap 5.3.

Before You Start

Make sure Bootstrap is installed in your Angular project:

npm install bootstrap bootstrap-icons

Add to angular.json under styles and scripts:

"styles": [
  "node_modules/bootstrap/dist/css/bootstrap.min.css",
  "node_modules/bootstrap-icons/font/bootstrap-icons.css",
  "src/styles.scss"
],
"scripts": [
  "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
]

That's all you need. Don't install @ng-bootstrap/ng-bootstrap unless you specifically need Angular-native Bootstrap components. For a navbar, plain Bootstrap CSS + JS is simpler and works fine.


The Basic Navbar Component

Create the component:

ng generate component navbar --standalone

Here's the HTML template. The key things to note are routerLink, routerLinkActive and the mobile toggle handling:

<!-- navbar.component.html -->
<nav class="navbar navbar-expand-lg bg-white border-bottom sticky-top shadow-sm">
  <div class="container-fluid">

    <!-- Brand -->
    <a class="navbar-brand fw-bold d-flex align-items-center gap-2"
      routerLink="/"
      style="color:#fd4766;">
      <span class="bg-danger text-white px-2 py-1 rounded" style="font-size:0.8rem;">BP</span>
      BootstrapPlanet
    </a>

    <!-- Mobile Toggle -->
    <button
      class="navbar-toggler border-0"
      type="button"
      (click)="isCollapsed = !isCollapsed"
      [attr.aria-expanded]="!isCollapsed"
      aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <!-- Nav Links -->
    <div class="navbar-collapse" [class.collapse]="isCollapsed">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">

        <li class="nav-item">
          <a class="nav-link"
            routerLink="/components"
            routerLinkActive="active"
            (click)="closeNav()">
            Components
          </a>
        </li>

        <li class="nav-item">
          <a class="nav-link"
            routerLink="/tutorials"
            routerLinkActive="active"
            (click)="closeNav()">
            Tutorials
          </a>
        </li>

        <li class="nav-item">
          <a class="nav-link"
            routerLink="/angular"
            routerLinkActive="active"
            (click)="closeNav()">
            Angular
          </a>
        </li>

        <!-- Dropdown -->
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle"
            href="#"
            role="button"
            data-bs-toggle="dropdown">
            More
          </a>
          <ul class="dropdown-menu">
            <li>
              <a class="dropdown-item"
                routerLink="/vs"
                routerLinkActive="active"
                (click)="closeNav()">
                Comparisons
              </a>
            </li>
            <li>
              <a class="dropdown-item"
                routerLink="/templates"
                routerLinkActive="active"
                (click)="closeNav()">
                Templates
              </a>
            </li>
          </ul>
        </li>

      </ul>

      <!-- Right side -->
      <div class="d-flex align-items-center gap-2">
        <a routerLink="/search" class="btn btn-sm btn-outline-secondary">
          <i class="bi bi-search"></i>
        </a>
        <a href="https://lettstartdesign.com"
          target="_blank"
          class="btn btn-sm text-white fw-semibold px-3"
          style="background:#fd4766;">
          Templates ↗
        </a>
      </div>
    </div>

  </div>
</nav>

Now the component TypeScript:

// navbar.component.ts
import { Component } from '@angular/core'
import { RouterLink, RouterLinkActive } from '@angular/router'
import { CommonModule } from '@angular/common'

@Component({
  selector: 'app-navbar',
  standalone: true,
  imports: [RouterLink, RouterLinkActive, CommonModule],
  templateUrl: './navbar.component.html'
})
export class NavbarComponent {
  isCollapsed = true

  closeNav() {
    this.isCollapsed = true
  }
}

The isCollapsed boolean controls mobile visibility. When a link is clicked, closeNav() collapses it back. Simple and reliable — no Bootstrap JS events fighting Angular's change detection.


Active Route Highlighting

routerLinkActive="active" does exactly what you expect — adds the active CSS class when the route matches.

One gotcha: the home route (/) will match every route because every URL starts with /. Fix it with routerLinkActiveOptions:

<a class="nav-link"
  routerLink="/"
  routerLinkActive="active"
  [routerLinkActiveOptions]="{ exact: true }">
  Home
</a>

Without exact: true your home link will always appear active no matter what page you're on. I've seen this trip people up more times than I can count.


Closing the Dropdown on Route Change

If you're using Bootstrap's dropdown in the navbar and navigating via routerLink, you might find the dropdown stays open after clicking a link. Fix this by subscribing to router events:

import { Component, OnInit } from '@angular/core'
import { Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router'
import { CommonModule } from '@angular/common'
import { filter } from 'rxjs/operators'

@Component({
  selector: 'app-navbar',
  standalone: true,
  imports: [RouterLink, RouterLinkActive, CommonModule],
  templateUrl: './navbar.component.html'
})
export class NavbarComponent implements OnInit {
  isCollapsed = true

  constructor(private router: Router) {}

  ngOnInit() {
    // Close navbar on any navigation
    this.router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe(() => {
        this.isCollapsed = true
        // Close any open Bootstrap dropdowns
        document.querySelectorAll('.dropdown-menu.show').forEach(el => {
          el.classList.remove('show')
        })
        document.querySelectorAll('.dropdown-toggle.show').forEach(el => {
          el.classList.remove('show')
          el.setAttribute('aria-expanded', 'false')
        })
      })
  }

  closeNav() {
    this.isCollapsed = true
  }
}

This subscribes to NavigationEnd events and closes both the mobile navbar and any open dropdowns. Cleaner than managing state in individual link click handlers.


Dark Navbar Variant

For a dark themed navbar — common in admin dashboards — just change the background and add data-bs-theme="dark":

<nav class="navbar navbar-expand-lg sticky-top"
  data-bs-theme="dark"
  style="background:#0d0d0d;border-bottom:1px solid #222;">
  <!-- everything else stays the same -->
</nav>

Bootstrap 5.3's data-bs-theme="dark" automatically inverts link colors, the toggler icon and dropdown menus. No extra CSS needed.


Using the Navbar Component

Add to your app.component.html:

<app-navbar />
<router-outlet />

And import it in your app.component.ts:

import { NavbarComponent } from './navbar/navbar.component'

@Component({
  standalone: true,
  imports: [RouterOutlet, NavbarComponent],
  ...
})

A Note on ng-bootstrap

You might be wondering why I'm not using ng-bootstrap here. Honest answer: for a navbar, you don't need it. ng-bootstrap is useful for complex components like datepickers, typeaheads and modals where you want deep Angular integration. For a navbar where Bootstrap's JS handles the toggle, plain Bootstrap CSS + JS is simpler and easier to maintain.

If you're building a component library or a large application where you want everything to feel native Angular, ng-bootstrap is worth it. But for most projects — especially admin dashboards — I find the overhead not worth it.

The navbar I've shown here has been my go-to for Angular projects for the past few years. It's simple, it works, and it doesn't fight Angular's change detection.

Frequently Asked Questions

Depends on your project. ng-bootstrap gives you Angular-native components with proper change detection and no jQuery. Bootstrap CSS only is simpler and gives you more control — you handle the JS interactions yourself with Angular. For most projects I'd use Bootstrap CSS + Bootstrap JS bundle directly, unless you need deep Angular integration like reactive forms inside modals.
Use RouterLinkActive directive: <a routerLink='/home' routerLinkActive='active' class='nav-link'>Home</a>. Angular automatically adds the active class when the route matches. Use [routerLinkActiveOptions]="{exact: true}" on the home route to prevent it always being active.
Track the collapsed state in a boolean variable. Add a click handler on each nav-link that sets isCollapsed = true. Or use the Bootstrap Collapse JS directly: collapse.hide() on each navigation event using Router events subscription.
Yes. Just import RouterLink, RouterLinkActive from @angular/router in the imports array of your standalone component. Bootstrap CSS works the same regardless of whether you use NgModules or standalone components.
ng-bootstrap is maintained by the Angular team and follows Angular's API patterns closely. ngx-bootstrap is older and has more components but is sometimes slower to update for new Angular versions. For Angular 21 I'd recommend ng-bootstrap — it's better maintained and the API feels more natural in modern Angular.

Related

Need a Full Angular + Bootstrap Admin Dashboard?

Marvel Angular Dashboard — Angular 21 + Bootstrap 5 with 50+ components and dark mode.

Browse Templates →

Use code FIRST30 for 30% off.