Bootstrap Header: 16 Hero, Sticky and Dark Header Examples

Bootstrap core has no .header class, and a lot of people lose twenty minutes looking for one. What you build instead is a header element wrapped around a navbar, on a framework that runs on 74.8% of the sites whose CSS framework W3Techs can identify (October 2026).

Below are 16 Bootstrap header examples you can copy, followed by a guide to building, theming and fixing one.

By Bogdan Sandu ยท Updated October 29, 2026

Every example runs on Bootstrap 5.3.8 from the jsDelivr CDN. Add these tags to your page, then paste an example's HTML, CSS and JS.

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.2/font/bootstrap-icons.min.css" rel="stylesheet" integrity="sha384-nWN3KqaaVcbEsCjLSV+2jMjh62Iny/+mN3srM8TZeM8N6aj7eDl5wwYggjAJ4/sJ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>

Navbar and hero headers

The top of a landing page is a navbar plus a hero, and Bootstrap builds both with the same grid, display headings and button variables. These four cover an announcement bar, a signup hero, a split hero with a photo and a product header with a screenshot.

Announcement bar, navbar and hero

  • alert-dismissible
  • data-bs-dismiss="alert"
  • navbar-expand-md
  • display-5

Close the announcement with the X. On a phone, tap the toggler to open the menu.

The top strip is a dismissible alert with rounded-0 and mb-0, so the close button removes it with data-bs-dismiss="alert" and no custom script. Under it sits a container navbar with centered links (mx-auto) and a centered hero built from display-5, lead and two buttons recolored through --bs-btn-* variables.

View code
<header class="bhd-bake">
  <div class="alert alert-dismissible fade show rounded-0 border-0 mb-0 py-2 text-center bhd-bake-bar" data-bs-theme="dark" role="alert">
    <span class="small">Free delivery on sourdough boxes until Sunday. <a href="#" class="alert-link">See this week's menu</a></span>
    <button type="button" class="btn-close py-2" data-bs-dismiss="alert" aria-label="Close announcement"></button>
  </div>
  <nav class="navbar navbar-expand-md bhd-bake-nav" aria-label="Main">
    <div class="container">
      <a class="navbar-brand d-flex align-items-center gap-2" href="#">
        <svg width="34" height="34" viewBox="0 0 34 34" aria-hidden="true"><circle cx="17" cy="17" r="17" fill="#3b2a1f"/><path d="M9 20c0-5 3.6-8.5 8-8.5s8 3.5 8 8.5z" fill="#fbf5ec"/><path d="M13 15.5l2 3M17 14.5v3.5M21 15.5l-2 3" stroke="#3b2a1f" stroke-width="1.6" stroke-linecap="round"/></svg>
        Kettle &amp; Crumb
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-bake-menu" aria-controls="bhd-bake-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-bake-menu">
        <ul class="navbar-nav mx-auto mb-2 mb-md-0">
          <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Breads</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Pastries</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Classes</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Visit</a></li>
        </ul>
        <a class="btn bhd-bake-cta mb-3 mb-md-0" href="#">Order for pickup</a>
      </div>
    </div>
  </nav>
  <div class="container text-center py-5 px-4">
    <h1 class="display-5 fw-bold bhd-bake-title mb-3">Baked before sunrise, gone by noon</h1>
    <p class="lead mx-auto mb-4 bhd-bake-lead">Naturally leavened loaves, laminated pastries and a short daily menu from a corner bakery that opens at 6:30.</p>
    <div class="d-flex flex-column flex-sm-row justify-content-center gap-2">
      <a class="btn btn-lg bhd-bake-cta" href="#">See today's bakes</a>
      <a class="btn btn-lg bhd-bake-ghost" href="#">Book a bread class</a>
    </div>
  </div>
</header>

Centered hero with an email signup

  • needs-validation
  • checkValidity()
  • invalid-feedback
  • row g-2

Submit the form empty to see the validation, then enter an email.

A centered hero whose call to action is an email form. The form uses the Bootstrap validation pattern (novalidate, checkValidity() and .was-validated) and swaps itself for a success message once the address is valid. The field and button sit in a row g-2 grid so they stack cleanly on a phone instead of squeezing into one input group.

View code
<header class="bhd-tide">
  <nav class="navbar navbar-expand-md" aria-label="Main">
    <div class="container">
      <a class="navbar-brand d-flex align-items-center gap-2 fw-bold" href="#">
        <svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><rect width="30" height="30" rx="9" fill="#0f5c63"/><path d="M6 17c3-3 6-3 9 0s6 3 9 0M6 12c3-3 6-3 9 0s6 3 9 0" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
        Tidewell
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-tide-menu" aria-controls="bhd-tide-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-tide-menu">
        <ul class="navbar-nav ms-auto mb-3 mb-md-0">
          <li class="nav-item"><a class="nav-link" href="#">Features</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Templates</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Pricing</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Sign in</a></li>
        </ul>
      </div>
    </div>
  </nav>
  <div class="container text-center px-4 pt-4 pt-md-5 pb-5">
    <h1 class="display-5 fw-bold mx-auto bhd-tide-title">Newsletters people actually open</h1>
    <p class="lead text-body-secondary mx-auto mb-4 bhd-tide-lead">Write once, send to every inbox, and see who read past the first paragraph. Tidewell is in private beta for independent writers.</p>
    <form class="mx-auto text-start bhd-tide-form" id="bhd-tide-form" novalidate>
      <div class="row g-2">
        <div class="col-sm">
          <label class="visually-hidden" for="bhd-tide-email">Email address</label>
          <input class="form-control form-control-lg" type="email" id="bhd-tide-email" placeholder="you@example.com" autocomplete="email" required>
          <div class="invalid-feedback">Enter an email address like name@example.com.</div>
        </div>
        <div class="col-sm-auto d-grid">
          <button class="btn btn-lg bhd-tide-btn" type="submit">Join the beta</button>
        </div>
      </div>
    </form>
    <div class="alert alert-success d-none mx-auto mb-0 bhd-tide-form" id="bhd-tide-done" role="status">You are on the list. We will email you when your seat opens.</div>
    <p class="small text-body-secondary mt-3 mb-0">Free up to 1,000 subscribers. No card needed.</p>
  </div>
</header>

Split hero with a photo

  • row align-items-center
  • col-md-6
  • img-fluid
  • position-absolute

On a phone the links collapse behind the toggler. Tap it to open the menu.

The hero is a two-column grid row with align-items-center: copy on the left, photo on the right, and the order flips back to stacked under the md breakpoint. A small rating card is pinned to the photo with position-absolute utilities, and the custom CSS only sets the palette and the photo shape.

View code
<header class="bhd-north">
  <nav class="navbar navbar-expand-md" aria-label="Main">
    <div class="container">
      <a class="navbar-brand fw-bold bhd-north-brand" href="#">Northbound</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-north-menu" aria-controls="bhd-north-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-north-menu">
        <ul class="navbar-nav me-auto mb-2 mb-md-0">
          <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Trips</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Destinations</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Guides</a></li>
        </ul>
        <a class="btn bhd-north-btn btn-sm px-3 mb-3 mb-md-0" href="#">Plan a trip</a>
      </div>
    </div>
  </nav>
  <div class="container py-4 py-md-5">
    <div class="row align-items-center g-4 g-lg-5">
      <div class="col-md-6">
        <h1 class="display-5 fw-bold mb-3">Small-group trips through the Norwegian fjords</h1>
        <p class="lead bhd-north-muted mb-4">Eight days, twelve travelers, one local guide. Ferries, ridge hikes and cabins booked for you.</p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-lg bhd-north-btn" href="#">See June dates</a>
          <a class="btn btn-lg btn-link bhd-north-link" href="#">Read the itinerary</a>
        </div>
      </div>
      <div class="col-md-6">
        <div class="position-relative">
          <img src="fjord.webp" class="img-fluid bhd-north-photo" width="800" height="600" alt="A deep blue fjord between steep granite cliffs, seen from a rocky ledge">
          <div class="position-absolute bottom-0 start-0 m-3 bg-white rounded-3 shadow-sm px-3 py-2 d-flex align-items-center gap-2">
            <i class="bi bi-star-fill bhd-north-star" aria-hidden="true"></i>
            <span class="small"><strong>4.9</strong> from 2,140 travelers</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</header>

Product header with an app screenshot

  • navbar-expand-md
  • inline SVG
  • overflow-hidden
  • --bs-btn-*

On a phone the links collapse behind the toggler. Tap it to open the menu.

A software launch header: navbar, centered pitch and an app screenshot that peeks up from the bottom edge. The screenshot is inline SVG inside a bordered frame, and overflow-hidden on the header crops it so the section keeps a sensible height. Swap the SVG for a real PNG of your product with width and height set.

View code
<header class="bhd-plot overflow-hidden">
  <nav class="navbar navbar-expand-md" aria-label="Main">
    <div class="container">
      <a class="navbar-brand d-flex align-items-center gap-2 fw-bold" href="#">
        <svg width="28" height="28" viewBox="0 0 28 28" aria-hidden="true"><rect width="28" height="28" rx="7" fill="#5b21b6"/><rect x="6" y="7" width="11" height="3" rx="1.5" fill="#fff"/><rect x="6" y="12.5" width="16" height="3" rx="1.5" fill="#c4b5fd"/><rect x="6" y="18" width="8" height="3" rx="1.5" fill="#fff"/></svg>
        Plotline
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-plot-menu" aria-controls="bhd-plot-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-plot-menu">
        <ul class="navbar-nav mx-auto mb-2 mb-md-0">
          <li class="nav-item"><a class="nav-link" href="#">Roadmaps</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Integrations</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Pricing</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Changelog</a></li>
        </ul>
        <div class="d-flex gap-2 mb-3 mb-md-0">
          <a class="btn btn-outline-secondary bhd-plot-soft" href="#">Log in</a>
          <a class="btn bhd-plot-btn" href="#">Try it free</a>
        </div>
      </div>
    </div>
  </nav>
  <div class="container text-center px-4 pt-4 pt-md-5">
    <h1 class="display-5 fw-bold mx-auto bhd-plot-title">Roadmaps your whole team can read</h1>
    <p class="lead text-body-secondary mx-auto mb-4 bhd-plot-lead">Drag ideas into quarters, link them to issues and share a read-only view with customers.</p>
    <div class="d-flex flex-column flex-sm-row justify-content-center gap-2 mb-5">
      <a class="btn btn-lg bhd-plot-btn" href="#">Start a free roadmap</a>
      <a class="btn btn-lg btn-outline-secondary bhd-plot-soft" href="#">Watch a 2-minute tour</a>
    </div>
    <div class="bhd-plot-shot mx-auto">
      <svg viewBox="0 0 960 420" role="img" aria-label="Plotline app showing a roadmap board with three quarter columns of cards" class="d-block w-100 h-auto">
        <rect width="960" height="420" fill="#fff"/>
        <rect width="960" height="40" fill="#f4f2fa"/>
        <circle cx="22" cy="20" r="6" fill="#e4dff2"/><circle cx="42" cy="20" r="6" fill="#e4dff2"/><circle cx="62" cy="20" r="6" fill="#e4dff2"/>
        <rect x="360" y="12" width="240" height="16" rx="8" fill="#e4dff2"/>
        <rect y="40" width="190" height="380" fill="#faf9fd"/>
        <rect x="24" y="64" width="110" height="12" rx="6" fill="#5b21b6"/>
        <rect x="24" y="96" width="140" height="10" rx="5" fill="#ddd6f3"/>
        <rect x="24" y="120" width="120" height="10" rx="5" fill="#ddd6f3"/>
        <rect x="24" y="144" width="130" height="10" rx="5" fill="#ddd6f3"/>
        <rect x="24" y="168" width="100" height="10" rx="5" fill="#ddd6f3"/>
        <rect x="222" y="64" width="200" height="14" rx="7" fill="#1f1640"/>
        <rect x="222" y="100" width="230" height="300" rx="10" fill="#f6f4fc"/>
        <rect x="472" y="100" width="230" height="300" rx="10" fill="#f6f4fc"/>
        <rect x="722" y="100" width="216" height="300" rx="10" fill="#f6f4fc"/>
        <rect x="238" y="116" width="60" height="10" rx="5" fill="#8b7bb8"/>
        <rect x="488" y="116" width="60" height="10" rx="5" fill="#8b7bb8"/>
        <rect x="738" y="116" width="60" height="10" rx="5" fill="#8b7bb8"/>
        <rect x="238" y="140" width="198" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="252" y="154" width="40" height="8" rx="4" fill="#16a34a"/>
        <rect x="252" y="172" width="150" height="10" rx="5" fill="#3b3355"/>
        <rect x="252" y="190" width="100" height="8" rx="4" fill="#cbc3e3"/>
        <rect x="238" y="222" width="198" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="252" y="236" width="40" height="8" rx="4" fill="#7c3aed"/>
        <rect x="252" y="254" width="130" height="10" rx="5" fill="#3b3355"/>
        <rect x="252" y="272" width="90" height="8" rx="4" fill="#cbc3e3"/>
        <rect x="488" y="140" width="198" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="502" y="154" width="40" height="8" rx="4" fill="#d97706"/>
        <rect x="502" y="172" width="160" height="10" rx="5" fill="#3b3355"/>
        <rect x="502" y="190" width="110" height="8" rx="4" fill="#cbc3e3"/>
        <rect x="488" y="222" width="198" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="502" y="236" width="40" height="8" rx="4" fill="#7c3aed"/>
        <rect x="502" y="254" width="120" height="10" rx="5" fill="#3b3355"/>
        <rect x="502" y="272" width="80" height="8" rx="4" fill="#cbc3e3"/>
        <rect x="488" y="304" width="198" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="502" y="318" width="40" height="8" rx="4" fill="#16a34a"/>
        <rect x="502" y="336" width="140" height="10" rx="5" fill="#3b3355"/>
        <rect x="738" y="140" width="184" height="70" rx="8" fill="#fff" stroke="#e4dff2"/>
        <rect x="752" y="154" width="40" height="8" rx="4" fill="#d97706"/>
        <rect x="752" y="172" width="130" height="10" rx="5" fill="#3b3355"/>
        <rect x="752" y="190" width="70" height="8" rx="4" fill="#cbc3e3"/>
      </svg>
    </div>
  </div>
</header>

Dark and photo headers

data-bs-theme="dark" on the header switches every component inside it to the dark palette, so a dark header over a light page takes one attribute. The photo header uses a solid translucent overlay to keep the text readable.

Background photo with a solid overlay

  • data-bs-theme="dark"
  • position-relative
  • object-fit-cover
  • bg-transparent

On a phone, tap the toggler to see how the open menu keeps its own background.

The photo is a real img stretched behind the content with position-absolute and object-fit-cover, and a single translucent layer (rgba, no gradient) darkens it for contrast. The transparent navbar takes data-bs-theme="dark" so links and the toggler icon turn light, and an inner wrapper gives the opened mobile menu its own background.

View code
<header class="bhd-photo position-relative text-white" data-bs-theme="dark">
  <img src="city-skyline.webp" class="position-absolute top-0 start-0 w-100 h-100 object-fit-cover" width="800" height="600" alt="">
  <div class="position-absolute top-0 start-0 w-100 h-100 bhd-photo-shade"></div>
  <nav class="navbar navbar-expand-md bg-transparent position-relative" aria-label="Main">
    <div class="container">
      <a class="navbar-brand fw-bold" href="#">Meridian Summit</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-photo-menu" aria-controls="bhd-photo-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-photo-menu">
        <div class="bhd-photo-drawer d-md-flex align-items-md-center w-100">
          <ul class="navbar-nav ms-md-auto me-md-3">
            <li class="nav-item"><a class="nav-link" href="#">Speakers</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Agenda</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Venue</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Sponsors</a></li>
          </ul>
          <a class="btn btn-light btn-sm px-3 mt-2 mt-md-0" href="#">Get tickets</a>
        </div>
      </div>
    </div>
  </nav>
  <div class="container position-relative py-5 bhd-photo-body">
    <p class="mb-3 d-flex flex-wrap gap-3 bhd-photo-meta">
      <span><i class="bi bi-calendar-event me-1" aria-hidden="true"></i>June 9 to 11, 2027</span>
      <span><i class="bi bi-geo-alt me-1" aria-hidden="true"></i>Riverside Hall, Chicago</span>
    </p>
    <h1 class="display-4 fw-bold mb-3">Three days on cities that work for the people in them</h1>
    <p class="lead mb-4 bhd-photo-lead">Urban planners, transit engineers and architects on stage, plus walking tours of the neighborhoods they talk about.</p>
    <div class="d-flex flex-wrap gap-2">
      <a class="btn btn-lg btn-light fw-semibold" href="#">Get early-bird tickets</a>
      <a class="btn btn-lg btn-outline-light" href="#">See the speakers</a>
    </div>
  </div>
</header>

Dark agency header

  • data-bs-theme="dark"
  • bg-body
  • border-bottom
  • display-3

On a phone, tap the toggler to see how the open menu keeps its own background.

One data-bs-theme="dark" attribute on the header turns bg-body, text-body-secondary, borders and the navbar into the dark palette. The custom CSS sets a near-black --bs-body-bg on the header and a lime accent for the call to action, and the hero is plain display-3 type with a row of studio stats.

View code
<header class="bhd-studio bg-body text-body" data-bs-theme="dark">
  <nav class="navbar navbar-expand-md border-bottom" aria-label="Main">
    <div class="container">
      <a class="navbar-brand fw-bold d-flex align-items-center gap-2" href="#">
        <svg width="26" height="26" viewBox="0 0 26 26" aria-hidden="true"><circle cx="8" cy="8" r="5" fill="#d9f99d"/><circle cx="18" cy="8" r="3.5" fill="#d9f99d"/><circle cx="8" cy="18" r="3.5" fill="#d9f99d"/><circle cx="18" cy="18" r="2" fill="#d9f99d"/></svg>
        Halftone
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-studio-menu" aria-controls="bhd-studio-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-studio-menu">
        <ul class="navbar-nav ms-auto mb-2 mb-md-0 me-md-3">
          <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Work</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Services</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Studio</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Journal</a></li>
        </ul>
        <a class="btn bhd-studio-btn mb-3 mb-md-0" href="#">Start a project</a>
      </div>
    </div>
  </nav>
  <div class="container py-5">
    <h1 class="display-3 fw-bold mb-4 bhd-studio-title">We design brands that still look right in ten years.</h1>
    <p class="lead text-body-secondary mb-5 bhd-studio-lead">Identity, packaging and websites for food, hospitality and independent retail. A team of nine in Porto.</p>
    <div class="row row-cols-2 row-cols-md-4 g-3 border-top pt-4">
      <div class="col"><div class="fs-3 fw-bold">140+</div><div class="small text-body-secondary">brands launched</div></div>
      <div class="col"><div class="fs-3 fw-bold">12</div><div class="small text-body-secondary">years in practice</div></div>
      <div class="col"><div class="fs-3 fw-bold">9</div><div class="small text-body-secondary">designers</div></div>
      <div class="col"><div class="fs-3 fw-bold">3 wk</div><div class="small text-body-secondary">average first draft</div></div>
    </div>
  </div>
</header>

Developer tool header themed with CSS variables

  • --bs-body-bg
  • --bs-emphasis-color
  • data-bs-theme="dark"
  • font-monospace

On a phone, tap the toggler to see how the open menu keeps its own background.

A dark header where the palette comes from overriding the 5.3 root variables (--bs-body-bg, --bs-body-color, --bs-border-color, --bs-link-color) on one prefixed wrapper, so every component inside follows. The right column is a terminal card built from a card, a card-header and font-monospace text.

View code
<header class="bhd-kiln bg-body text-body" data-bs-theme="dark">
  <nav class="navbar navbar-expand-md border-bottom" aria-label="Main">
    <div class="container">
      <a class="navbar-brand font-monospace fw-bold d-flex align-items-center gap-2" href="#">
        <i class="bi bi-terminal-fill bhd-kiln-accent" aria-hidden="true"></i>kiln
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-kiln-menu" aria-controls="bhd-kiln-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-kiln-menu">
        <ul class="navbar-nav me-auto mb-2 mb-md-0">
          <li class="nav-item"><a class="nav-link" href="#">Docs</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Plugins</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Blog</a></li>
        </ul>
        <div class="d-flex align-items-center gap-3 mb-3 mb-md-0">
          <span class="badge rounded-pill border bhd-kiln-ver">v2.4.1</span>
          <a class="btn btn-sm bhd-kiln-btn" href="#">Get started</a>
        </div>
      </div>
    </div>
  </nav>
  <div class="container py-5">
    <div class="row align-items-center g-4">
      <div class="col-md-6">
        <h1 class="display-5 fw-bold mb-3">Build static sites in milliseconds, not minutes</h1>
        <p class="lead mb-4 bhd-kiln-muted">kiln compiles Markdown, templates and assets with incremental rebuilds, so the preview updates before you switch windows.</p>
        <div class="d-flex flex-wrap gap-3 align-items-center">
          <a class="btn btn-lg bhd-kiln-btn" href="#">Read the quick start</a>
          <a href="#" class="fw-semibold">Browse 60 starter themes</a>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card bhd-kiln-term shadow">
          <div class="card-header d-flex align-items-center gap-2 py-2">
            <span class="bhd-kiln-dot"></span><span class="bhd-kiln-dot"></span><span class="bhd-kiln-dot"></span>
            <span class="small bhd-kiln-muted ms-2 font-monospace">~/my-site</span>
          </div>
          <div class="card-body font-monospace small">
            <p class="mb-1"><span class="bhd-kiln-accent">$</span> kiln new my-site --theme paper</p>
            <p class="mb-1 bhd-kiln-muted">Created 14 files in 38 ms</p>
            <p class="mb-1"><span class="bhd-kiln-accent">$</span> kiln dev</p>
            <p class="mb-1 bhd-kiln-muted">Serving on port 4100</p>
            <p class="mb-0"><span class="bhd-kiln-ok">rebuilt</span> posts/hello.md in 6 ms</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</header>

Inner page headers

Pages below the homepage need a smaller header: a breadcrumb, a title, some meta and the actions for that page. These four use breadcrumbs, badges, nav tabs and a two-row shop header with a cart badge.

Blog article header with meta

  • ratio ratio-21x9
  • figure-caption
  • rounded-circle
  • vr

An editorial article header: category link, serif headline, standfirst and an author row split by the .vr divider, then a wide lead photo. The photo sits in a ratio ratio-21x9 box with object-fit-cover so any upload crops to the same banner shape, and the caption uses figure-caption.

View code
<header class="bhd-post">
  <nav class="navbar navbar-expand-md border-bottom" aria-label="Main">
    <div class="container">
      <a class="navbar-brand bhd-post-brand" href="#">The Field Report</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-post-menu" aria-controls="bhd-post-menu" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="bhd-post-menu">
        <ul class="navbar-nav ms-auto mb-2 mb-md-0">
          <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Travel</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Food</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Gear</a></li>
          <li class="nav-item"><a class="nav-link" href="#">Subscribe</a></li>
        </ul>
      </div>
    </div>
  </nav>
  <div class="container py-4 py-md-5">
    <div class="mx-auto bhd-post-col">
      <a href="#" class="bhd-post-cat small fw-semibold text-uppercase">Road trips</a>
      <h1 class="bhd-post-title mt-2 mb-3">Four days on a cliffside coast road, one small rental car</h1>
      <p class="lead text-body-secondary mb-4">Where to stop, which bends to take slowly and the one village worth arriving at before the tour buses.</p>
      <div class="d-flex flex-wrap align-items-center gap-3 small text-body-secondary mb-4">
        <span class="d-flex align-items-center gap-2">
          <span class="bhd-post-avatar rounded-circle d-inline-flex align-items-center justify-content-center fw-semibold" aria-hidden="true">MO</span>
          <span>By <a href="#" class="text-body fw-semibold">Mara Okafor</a></span>
        </span>
        <span class="vr"></span>
        <time datetime="2026-10-12">October 12, 2026</time>
        <span class="vr"></span>
        <span>9 min read</span>
      </div>
    </div>
    <figure class="mb-0">
      <div class="ratio ratio-21x9 rounded-3 overflow-hidden">
        <img src="coast-road.webp" class="object-fit-cover" width="800" height="600" alt="A pine-covered headland dropping into the sea, with a road cut into the hillside">
      </div>
      <figcaption class="figure-caption mt-2">The coast road above the bay, an hour before sunset.</figcaption>
    </figure>
  </div>
</header>

Ecommerce header with a utility bar and cart badge

  • badge position-absolute
  • translate-middle
  • form-select-sm
  • nav-scroller pattern

Three rows: a dark utility bar with shipping info and a currency select, the main navbar with search and icon buttons, and a category row that scrolls sideways on phones. The cart count is a rounded-pill badge placed with position-absolute, top-0, start-100 and translate-middle, with visually-hidden text so screen readers hear the number in context.

View code
<header class="bhd-shop">
  <div class="bhd-shop-util small" data-bs-theme="dark">
    <div class="container d-flex align-items-center justify-content-between gap-3 py-1">
      <span><i class="bi bi-truck me-1" aria-hidden="true"></i>Free shipping on orders over $75</span>
      <div class="d-flex align-items-center gap-3">
        <a href="#" class="d-none d-md-inline">Help</a>
        <a href="#" class="d-none d-md-inline">Track an order</a>
        <label class="visually-hidden" for="bhd-shop-cur">Currency</label>
        <select class="form-select form-select-sm bhd-shop-cur" id="bhd-shop-cur">
          <option>USD</option>
          <option>CAD</option>
          <option>EUR</option>
        </select>
      </div>
    </div>
  </div>
  <nav class="navbar navbar-expand-md bg-body border-bottom" aria-label="Main">
    <div class="container flex-nowrap gap-2">
      <a class="navbar-brand fw-bold d-flex align-items-center gap-2 me-md-4" href="#">
        <i class="bi bi-flower1 bhd-shop-logo" aria-hidden="true"></i>Fernhouse
      </a>
      <form class="flex-grow-1 d-none d-md-block" role="search">
        <label class="visually-hidden" for="bhd-shop-q">Search plants and pots</label>
        <div class="input-group">
          <input class="form-control" type="search" id="bhd-shop-q" placeholder="Search plants, pots and soil">
          <button class="btn btn-outline-secondary" type="submit" aria-label="Search"><i class="bi bi-search" aria-hidden="true"></i></button>
        </div>
      </form>
      <div class="d-flex align-items-center gap-1 ms-auto">
        <a href="#" class="btn btn-link text-body bhd-shop-icon" aria-label="Account"><i class="bi bi-person" aria-hidden="true"></i></a>
        <a href="#" class="btn btn-link text-body bhd-shop-icon d-none d-sm-inline-flex" aria-label="Saved items"><i class="bi bi-heart" aria-hidden="true"></i></a>
        <a href="#" class="btn btn-link text-body bhd-shop-icon position-relative">
          <i class="bi bi-bag" aria-hidden="true"></i>
          <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bhd-shop-badge">3<span class="visually-hidden"> items in cart</span></span>
          <span class="visually-hidden">Cart</span>
        </a>
      </div>
    </div>
  </nav>
  <div class="border-bottom bg-body">
    <div class="container">
      <ul class="nav bhd-shop-cats flex-nowrap text-nowrap">
        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">New in</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Indoor plants</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Outdoor</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Pots and planters</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Care</a></li>
        <li class="nav-item"><a class="nav-link bhd-shop-sale" href="#">Sale</a></li>
      </ul>
    </div>
  </div>
  <div class="container py-3 d-md-none">
    <form role="search">
      <label class="visually-hidden" for="bhd-shop-qm">Search plants and pots</label>
      <input class="form-control" type="search" id="bhd-shop-qm" placeholder="Search plants, pots and soil">
    </form>
  </div>
</header>

Project page header with tabs

  • nav-underline
  • data-bs-toggle="tab"
  • tab-content
  • avatar stack

Click the tabs under the title.

A dashboard page header: a compact dark app bar, then the project title with a status badge, a stacked row of member avatars, actions, and nav-underline tabs at the bottom edge. The tabs are real Bootstrap tabs (data-bs-toggle="tab" with role="tablist"), so the panes under the header switch without any custom script.

View code
<div class="bhd-proj">
  <header>
    <nav class="navbar navbar-expand bhd-proj-bar" data-bs-theme="dark" aria-label="App">
      <div class="container-fluid px-3 px-md-4">
        <a class="navbar-brand fw-bold fs-6 d-flex align-items-center gap-2" href="#"><i class="bi bi-compass" aria-hidden="true"></i>Atlas</a>
        <ul class="navbar-nav ms-auto small">
          <li class="nav-item"><a class="nav-link" href="#">Projects</a></li>
          <li class="nav-item d-none d-sm-block"><a class="nav-link" href="#">Reports</a></li>
          <li class="nav-item"><a class="nav-link" href="#" aria-label="Settings"><i class="bi bi-gear" aria-hidden="true"></i></a></li>
        </ul>
      </div>
    </nav>
    <div class="bg-body border-bottom">
      <div class="container-fluid px-3 px-md-4 pt-4">
        <div class="d-md-flex justify-content-between align-items-start gap-4">
          <div class="mb-3">
            <div class="d-flex flex-wrap align-items-center gap-2 mb-1">
              <h1 class="h3 fw-bold mb-0">Website redesign</h1>
              <span class="badge rounded-pill text-bg-success bhd-proj-status"><i class="bi bi-circle-fill me-1" aria-hidden="true"></i>On track</span>
            </div>
            <p class="text-body-secondary small mb-0">Due December 4, 2026. 38 of 61 tasks done.</p>
          </div>
          <div class="d-flex align-items-center gap-3 mb-3">
            <div class="d-flex bhd-proj-team" aria-label="5 members">
              <span class="bhd-proj-av" style="--bhd-av:#2563eb">JL</span>
              <span class="bhd-proj-av" style="--bhd-av:#9333ea">AK</span>
              <span class="bhd-proj-av" style="--bhd-av:#c2410c">TR</span>
              <span class="bhd-proj-av" style="--bhd-av:#0f766e">SM</span>
              <span class="bhd-proj-av bhd-proj-more">+1</span>
            </div>
            <a class="btn btn-sm btn-outline-secondary" href="#">Share</a>
            <a class="btn btn-sm btn-primary" href="#"><i class="bi bi-plus-lg me-1" aria-hidden="true"></i>Task</a>
          </div>
        </div>
        <ul class="nav nav-underline bhd-proj-tabs flex-nowrap text-nowrap" role="tablist">
          <li class="nav-item" role="presentation"><button class="nav-link active" id="bhd-proj-t1" data-bs-toggle="tab" data-bs-target="#bhd-proj-p1" type="button" role="tab" aria-controls="bhd-proj-p1" aria-selected="true">Overview</button></li>
          <li class="nav-item" role="presentation"><button class="nav-link" id="bhd-proj-t2" data-bs-toggle="tab" data-bs-target="#bhd-proj-p2" type="button" role="tab" aria-controls="bhd-proj-p2" aria-selected="false">Board</button></li>
          <li class="nav-item" role="presentation"><button class="nav-link" id="bhd-proj-t3" data-bs-toggle="tab" data-bs-target="#bhd-proj-p3" type="button" role="tab" aria-controls="bhd-proj-p3" aria-selected="false">Files <span class="badge rounded-pill text-bg-light border ms-1">12</span></button></li>
        </ul>
      </div>
    </div>
  </header>
  <div class="tab-content container-fluid px-3 px-md-4 py-4 bg-body-tertiary">
    <div class="tab-pane fade show active" id="bhd-proj-p1" role="tabpanel" aria-labelledby="bhd-proj-t1" tabindex="0">
      <p class="mb-0 small text-body-secondary">Overview: homepage and pricing page are in review, navigation is approved, and the content migration starts next week.</p>
    </div>
    <div class="tab-pane fade" id="bhd-proj-p2" role="tabpanel" aria-labelledby="bhd-proj-t2" tabindex="0">
      <p class="mb-0 small text-body-secondary">Board: 9 to do, 14 in progress, 38 done. Two cards are blocked by copy review.</p>
    </div>
    <div class="tab-pane fade" id="bhd-proj-p3" role="tabpanel" aria-labelledby="bhd-proj-t3" tabindex="0">
      <p class="mb-0 small text-body-secondary">Files: 12 uploads, including the final sitemap and two rounds of homepage mockups.</p>
    </div>
  </div>
</div>

Sticky, offcanvas and theme switching

Headers that react: one pins and shrinks as you scroll, one moves its menu into an offcanvas drawer on phones, one carries dropdowns for an app and one switches between light and dark mode.

Sticky header that shrinks on scroll

  • sticky-top
  • scroll event
  • classList.toggle
  • --bs-navbar-padding-y

Scroll inside the frame and watch the header tighten.

The header carries sticky-top, so it pins to the top of its scrolling parent. Here the parent is a scrollable box so the effect works inside the demo; on a real page drop the box and listen to window scroll instead. A few lines of JS toggle one class once the box scrolls past 24px, and that class lowers --bs-navbar-padding-y and adds a border and shadow.

View code
<div class="bhd-sticky-box" id="bhd-sticky-box" tabindex="0" aria-label="Scrollable article preview">
  <header class="sticky-top bhd-sticky" id="bhd-sticky-bar">
    <nav class="navbar navbar-expand" aria-label="Main">
      <div class="container">
        <a class="navbar-brand fw-bold bhd-sticky-brand" href="#">Lumen Weekly</a>
        <ul class="navbar-nav ms-auto align-items-center gap-1">
          <li class="nav-item d-none d-sm-block"><a class="nav-link" href="#">Science</a></li>
          <li class="nav-item d-none d-sm-block"><a class="nav-link" href="#">Culture</a></li>
          <li class="nav-item d-none d-md-block"><a class="nav-link" href="#">Archive</a></li>
          <li class="nav-item ms-2"><a class="btn btn-sm btn-dark px-3" href="#">Subscribe</a></li>
        </ul>
      </div>
    </nav>
  </header>
  <main class="container py-4">
    <h1 class="h2 fw-bold mb-3">The quiet return of the night train</h1>
    <p class="text-body-secondary">Sleeper routes that closed a decade ago are running again, and the carriages are fuller than the timetables predicted. We rode three of them in one week.</p>
    <p>The first leaves at 21:40. By the time the conductor finishes checking tickets the city has gone, and the only light in the corridor comes from a reading lamp two cabins down.</p>
    <p>Operators credit flight-shame, but the passengers we met mostly talked about time. A night on rails replaces a hotel and a morning flight, and nobody has to be at an airport at 5 a.m.</p>
    <p>The economics are harder. Sleeper carriages carry fewer people than seated ones, and each train needs staff awake all night. Most routes survive on public contracts.</p>
    <p class="mb-0">Still, the demand is real. Two of the three trains we took were sold out a month ahead.</p>
  </main>
</div>

Header with an offcanvas menu on phones

  • navbar-expand-md
  • offcanvas offcanvas-end
  • data-bs-toggle="offcanvas"
  • aria-labelledby

On a phone, tap the toggler to slide the menu in from the right.

The docs offcanvas navbar pattern: the toggler opens an .offcanvas instead of a collapse, and navbar-expand-md turns that panel back into an inline bar from 768px up. The panel holds the links, a booking button and contact details, it is labelled by its title, and data-bs-theme="dark" on the header gives it the dark palette.

View code
<header class="bhd-cairn" data-bs-theme="dark">
  <nav class="navbar navbar-expand-md" aria-label="Main">
    <div class="container">
      <a class="navbar-brand fw-bold d-flex align-items-center gap-2" href="#">
        <svg width="28" height="28" viewBox="0 0 28 28" aria-hidden="true"><path d="M3 24L12 7l5 9 3-5 5 13z" fill="#f2c14e"/></svg>
        Cairn Guides
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#bhd-cairn-menu" aria-controls="bhd-cairn-menu" aria-label="Open menu">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="offcanvas offcanvas-end bhd-cairn-panel" tabindex="-1" id="bhd-cairn-menu" aria-labelledby="bhd-cairn-menu-title">
        <div class="offcanvas-header border-bottom">
          <h2 class="offcanvas-title h5" id="bhd-cairn-menu-title">Cairn Guides</h2>
          <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close menu"></button>
        </div>
        <div class="offcanvas-body align-items-md-center">
          <ul class="navbar-nav ms-md-auto me-md-3 mb-4 mb-md-0">
            <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Courses</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Private guiding</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Expeditions</a></li>
            <li class="nav-item"><a class="nav-link" href="#">About us</a></li>
          </ul>
          <a class="btn bhd-cairn-btn" href="#">Book a course</a>
          <p class="small text-body-secondary mt-4 mb-0 d-md-none">Office open 8:00 to 18:00<br>+1 555 0142</p>
        </div>
      </div>
    </div>
  </nav>
  <div class="container py-5">
    <h1 class="display-5 fw-bold text-white mb-3 bhd-cairn-title">Learn to move safely in the high mountains</h1>
    <p class="lead mb-4 bhd-cairn-lead">Glacier travel, scrambling and winter skills courses with certified guides. Groups of four or fewer.</p>
    <a class="btn btn-lg bhd-cairn-btn" href="#">See winter dates</a>
  </div>
</header>

App header with notification and account dropdowns

  • dropdown-menu-end
  • data-bs-toggle="dropdown"
  • badge
  • dropdown-header

Click the bell or the avatar to open a menu.

A logged-in app header: brand, search on wider screens, a notification bell with an unread badge and an account menu. Both menus are standard dropdowns with dropdown-menu-end so they open toward the inside of the screen, and the bell button gets an aria-label that includes the unread count.

View code
<div class="bhd-desk bg-body-tertiary">
  <header class="bg-body border-bottom">
    <div class="container-fluid px-3 px-md-4 py-2 d-flex align-items-center gap-3">
      <a class="d-flex align-items-center gap-2 fw-bold text-body text-decoration-none me-auto me-md-0" href="#">
        <i class="bi bi-life-preserver bhd-desk-logo" aria-hidden="true"></i>Cobalt Desk
      </a>
      <form class="d-none d-md-block flex-grow-1 bhd-desk-search mx-md-4" role="search">
        <label class="visually-hidden" for="bhd-desk-q">Search tickets</label>
        <input class="form-control bg-body-tertiary" type="search" id="bhd-desk-q" placeholder="Search tickets, customers, macros">
      </form>
      <div class="dropdown">
        <button class="btn btn-link text-body position-relative bhd-desk-icon" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Notifications, 3 unread">
          <i class="bi bi-bell" aria-hidden="true"></i>
          <span class="position-absolute bhd-desk-dot rounded-circle"></span>
        </button>
        <div class="dropdown-menu dropdown-menu-end shadow bhd-desk-menu">
          <h2 class="dropdown-header h6">Notifications</h2>
          <a class="dropdown-item py-2" href="#"><strong>Ana P.</strong> replied to ticket #4821<br><span class="small text-body-secondary">2 min ago</span></a>
          <a class="dropdown-item py-2" href="#">SLA breach risk on 2 tickets<br><span class="small text-body-secondary">14 min ago</span></a>
          <a class="dropdown-item py-2" href="#">New macro shared by <strong>Leo M.</strong><br><span class="small text-body-secondary">1 hour ago</span></a>
          <hr class="dropdown-divider">
          <a class="dropdown-item small text-center" href="#">See all notifications</a>
        </div>
      </div>
      <div class="dropdown">
        <button class="btn btn-link p-0 text-decoration-none d-flex align-items-center gap-2 bhd-desk-user" type="button" id="bhd-desk-user" data-bs-toggle="dropdown" aria-expanded="false">
          <span class="bhd-desk-av rounded-circle d-inline-flex align-items-center justify-content-center fw-semibold">JD</span>
          <span class="d-none d-sm-inline text-body small fw-semibold">Jamie Doyle</span>
          <i class="bi bi-chevron-down small text-body-secondary" aria-hidden="true"></i>
          <span class="visually-hidden">Account menu</span>
        </button>
        <ul class="dropdown-menu dropdown-menu-end shadow">
          <li><span class="dropdown-item-text small text-body-secondary">jamie@cobaltdesk.test</span></li>
          <li><hr class="dropdown-divider"></li>
          <li><a class="dropdown-item" href="#"><i class="bi bi-person me-2" aria-hidden="true"></i>Profile</a></li>
          <li><a class="dropdown-item" href="#"><i class="bi bi-sliders me-2" aria-hidden="true"></i>Preferences</a></li>
          <li><a class="dropdown-item" href="#"><i class="bi bi-moon me-2" aria-hidden="true"></i>Set status to away</a></li>
          <li><hr class="dropdown-divider"></li>
          <li><a class="dropdown-item" href="#"><i class="bi bi-box-arrow-right me-2" aria-hidden="true"></i>Sign out</a></li>
        </ul>
      </div>
    </div>
  </header>
  <div class="container-fluid px-3 px-md-4 py-4">
    <h1 class="h4 fw-bold mb-3">Open tickets</h1>
    <div class="row g-3">
      <div class="col-6 col-md-3"><div class="bg-body border rounded-3 p-3"><div class="small text-body-secondary">Unassigned</div><div class="fs-4 fw-bold">18</div></div></div>
      <div class="col-6 col-md-3"><div class="bg-body border rounded-3 p-3"><div class="small text-body-secondary">Mine</div><div class="fs-4 fw-bold">7</div></div></div>
      <div class="col-6 col-md-3"><div class="bg-body border rounded-3 p-3"><div class="small text-body-secondary">Due today</div><div class="fs-4 fw-bold">5</div></div></div>
      <div class="col-6 col-md-3"><div class="bg-body border rounded-3 p-3"><div class="small text-body-secondary">Avg. reply</div><div class="fs-4 fw-bold">1h 12m</div></div></div>
    </div>
  </div>
</div>

Header with a light and dark mode switch

  • data-bs-theme
  • aria-pressed
  • bg-body
  • text-body-secondary

Click the moon button in the header.

The whole block is styled with color-mode-aware utilities (bg-body, text-body-secondary, border) and the secondary buttons read their colors from --bs-body-color and --bs-border-color, so switching data-bs-theme on the wrapper repaints everything at once. The toggle is a button with aria-pressed, and the JS only flips the attribute and swaps the icon. On a real site set the attribute on the html element and remember the choice.

View code
<div class="bhd-mode bg-body text-body" id="bhd-mode" data-bs-theme="light">
  <header>
    <nav class="navbar navbar-expand-md border-bottom" aria-label="Main">
      <div class="container">
        <a class="navbar-brand fw-bold d-flex align-items-center gap-2" href="#">
          <i class="bi bi-journal-richtext bhd-mode-logo" aria-hidden="true"></i>Paperlane
        </a>
        <div class="d-flex align-items-center gap-2 order-md-last">
          <button class="btn bhd-mode-ghost bhd-mode-btn" type="button" id="bhd-mode-btn" aria-pressed="false" aria-label="Dark mode">
            <i class="bi bi-moon-stars" id="bhd-mode-icon" aria-hidden="true"></i>
          </button>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bhd-mode-menu" aria-controls="bhd-mode-menu" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
        </div>
        <div class="collapse navbar-collapse" id="bhd-mode-menu">
          <ul class="navbar-nav mx-md-auto mb-2 mb-md-0">
            <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Notes</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Templates</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Apps</a></li>
            <li class="nav-item"><a class="nav-link" href="#">Pricing</a></li>
          </ul>
        </div>
      </div>
    </nav>
    <div class="container py-5 text-center">
      <h1 class="display-6 fw-bold mb-3">Notes that read well at 2&nbsp;a.m.</h1>
      <p class="lead text-body-secondary mx-auto mb-4 bhd-mode-lead">A calm writing app with a proper dark mode, offline sync and Markdown shortcuts that stay out of the way.</p>
      <div class="d-flex flex-column flex-sm-row justify-content-center gap-2">
        <a class="btn btn-lg bhd-mode-cta" href="#">Download for free</a>
        <a class="btn btn-lg bhd-mode-ghost" href="#">See what is new</a>
      </div>
    </div>
  </header>
</div>

What Is a Bootstrap Header?

Every header example in the docs is really a navbar. Bootstrap’s own documentation calls that component a “responsive navigation header”, and the header element around it is ordinary HTML that gives the bar a place in the page structure.

The navbar ships inside the Bootstrap CSS framework, so the styles and the Collapse and Offcanvas scripts all come from one package.

As of October 2026, the official docs list v5.3.8 as the current release, which shipped on August 25, 2025 (Bootstrap blog). Every class name in this article targets the 5.3 line.

Searches for a Bootstrap header also pull in the Bootstrap 3 .page-header class, a spacing wrapper around a page heading from a much older major version. Some people mean the hero section, the large banner that sits under the header. The .card-header strip at the top of a card gets mixed in too. MDB and CoreUI header components are different again, since they ship their own markup (MDB uses data-mdb-* attributes).

The navbar component has its own guide if you want it covered in isolation, the Bootstrap navbar one.

How to Build a Bootstrap Header Step by Step

Skip any one of these pieces and the menu usually stops working in a way that takes a while to trace.

  1. Add the HTML5 doctype and the viewport meta tag. Load the CSS in the head and the bundle script before the closing body tag, from jsDelivr (bootstrap@5.3.8).
  2. Open a header element, then a nav with the classes navbar, navbar-expand-lg, and bg-body-tertiary.
  3. Add a div with container-fluid inside the nav. Use container instead for a fixed-width layout.
  4. Add the brand: an a tag with navbar-brand, holding text or an img with explicit width and height.
  5. Add the toggler: a button with navbar-toggler, data-bs-toggle=”collapse”, data-bs-target=”#navbarNav”, aria-controls=”navbarNav”, aria-expanded=”false”, and aria-label=”Toggle navigation”. Put a span with navbar-toggler-icon inside it.
  6. Add a div with collapse and navbar-collapse and the id navbarNav. Inside it goes a ul.navbar-nav, where each link is an li.nav-item holding an a.nav-link. The current page gets the active class and aria-current=”page”.

The data-bs-target value and the collapse id must match exactly. A mismatch stops the menu from opening, and it’s the first thing I check when a toggler does nothing.

The bundle script includes Popper, which dropdowns need, along with popovers and tooltips. A header without a dropdown can load bootstrap.min.js alone and skip Popper, per the Bootstrap 5.3 docs.

Using a header element instead of a div has a practical effect. Placed directly in the body, it is exposed to assistive technology as the page banner, and the nav inside it as a navigation landmark.

How a Bootstrap Header Collapses on Small Screens

The navbar-expand-{breakpoint} class sets the width at which the links spread out in a row. Below that width they sit behind the toggler inside the collapse wrapper.

Choosing the breakpoint

Each breakpoint has its own expand class, with widths taken from the 5.3 breakpoints docs.

  • sm: 576px and up
  • md: 768px and up
  • lg: 992px and up
  • xl: 1200px and up
  • xxl: 1400px and up

Without an expand class the header collapses at every width, and plain navbar-expand does the opposite, so the links never fold.

These widths rest on min-width CSS media queries and a mobile-first approach. The collapsed layout is the base style, and the row layout is the override.

Pick the breakpoint from the longest realistic label set, not from device names. If the links wrap onto a second row at some width, move the expand class up one step.

Toggler and Collapse plugin

Bootstrap’s plugins have no special fallback when JavaScript is disabled (Bootstrap 5.3 docs). A header that starts collapsed stays collapsed.

The navbar extends the Collapse and Offcanvas plugins, and the collapse animation respects the prefers-reduced-motion setting.

Markup order sets where the toggler lands. After the brand, it sits on the far right. Put it before the brand and it moves to the left, so reversing the markup flips it.

The three-line icon is the familiar hamburger menu icon. The navbar-toggler-icon class draws it as a background SVG, so no icon font is involved.

What Can You Put Inside a Bootstrap Header?

Most of what a header needs has built-in support. That covers the brand, links, dropdowns, search forms and plain text, and flex and spacing utilities handle the rest.

The brand is navbar-brand on an anchor, holding text, an image or both. Links go in a navbar-nav list of nav-link items. A search form is a d-flex form with role=”search”, with buttons alongside it. For a short string such as a phone number or login status, navbar-text does the job.

Immediate children of the navbar use flex layout and default to justify-content: space-between (Bootstrap 5.3 docs). Add me-auto to the link list to keep links on the left and push the search form to the right.

Dropdowns need a wrapper. An li.nav-item with the dropdown class surrounds a nav-link that carries dropdown-toggle and data-bs-toggle=”dropdown”, the same pattern as the standalone Bootstrap dropdown.

Popper does not position dropdowns inside a navbar, since dynamic positioning is not needed there. They open on click, never on hover, and the docs describe that as an intentional design decision.

For icons, pick one set per header, such as the Bootstrap Icons library or Font Awesome. Mixing two sets makes stroke weights clash.

Icon links stack vertically inside a collapsed menu unless you wrap them in a d-flex container.

Keep the content short. A brand, a few links and a single primary action is plenty.

Fixed, Sticky, or Static: Positioning the Bootstrap Header

Use sticky-top on the header element for most pages. Reach for fixed-top only when you control the header height.

ClassStays in flowBody padding neededScroll behavior
Default (none)YesNoScrolls away with the page
.fixed-topNoYesStays at the top of the viewport
.sticky-topYesNoScrolls, then pins at the top
.sticky-lg-topYesNoPins only at 992px and up

Bootstrap’s z-index scale sets sticky at 1020 and fixed at 1030, below offcanvas at 1045 and modals at 1055 (Bootstrap 5.3 docs). A modal opens over either header, which is the behavior you want.

A fixed header leaves the document flow, and the docs warn it may need padding-top on the body to prevent overlap. Set the padding to the rendered header height, measured in dev tools.

Anchor links need the same value in scroll-padding-top on the html element. Otherwise the target heading lands under the bar.

Sticky has one catch. position: sticky only works inside its parent, so a sticky-top class on a nav that sits in a header element no taller than the nav never pins.

Put the class on the header element, and make that element a direct child of the body.

A sticky header keeps the menu within reach on long pages, the pattern usually called sticky navigation.

How to Change the Bootstrap Header Color and Add Dark Mode

Put data-bs-theme=”dark” on the nav and pick a background with a bg-* utility. That is the 5.3 method, and it replaces the older navbar-dark class.

The Bootstrap 5.3 navbar docs show a few combinations that work. A dark bar uses bg-dark with border-bottom and border-body, plus data-bs-theme=”dark”. A colored bar can use bg-primary with the same dark attribute. For a pale custom bar, set an inline background-color of #e3f2fd and pair it with data-bs-theme=”light”.

The attribute applies to whatever element carries it. On the html element it themes the whole page, and on the nav alone it gives a dark header over a light page. Dropdowns inside the nav follow it.

The history is a little messy. v5.2.0 moved navbar theming to CSS variables scoped to .navbar and deprecated navbar-light, and v5.3.0 then deprecated navbar-dark in favor of the attribute.

For a custom palette, override variables on one navbar instead of rewriting rules. Link, hover, active and brand colors each get their own variable, namely –bs-navbar-color, –bs-navbar-hover-color, –bs-navbar-active-color and –bs-navbar-brand-color.

Sass builds change the defaults at the source. $navbar-light-color and $navbar-dark-color set the base link colors.

Choose custom colors with contrast in mind. A tool that generates accessible color palettes narrows the options before you touch any CSS.

Bootstrap’s own documentation header is a working reference. Its light, dark and auto picker is built from the same navbar and dropdown components, and the color modes docs print its script.

Bootstrap ships no built-in color mode picker, and the attribute does not follow the operating system on its own. The docs suggest placing the toggler script at the top of the page to reduce flicker on reload.

A Sass option, $color-mode-type: media-query, makes modes follow prefers-color-scheme automatically. It also removes per-component theming, so a dark header on a light page needs the default data attribute approach.

Collapse Menu or Offcanvas Panel for the Mobile Header?

If the open menu stays short enough to fit under the bar, use the Collapse plugin. Once it outgrows that, switch to an offcanvas panel.

Both patterns sit in the same navbar, and both turn back into a normal bar at the breakpoint you set with navbar-expand-lg or a sibling class. Offcanvas navbars arrived in v5.1.0, so v5.0 snippets will not have them (Bootstrap migration notes).

Collapse menu

The collapse menu takes the least markup, just one toggler and one collapse wrapper. It works with every position class and opens in place, so the menu stays attached to the bar.

The downsides are spacing and length. Padding cannot go on the .collapse element, so spacing needs an inner wrapper. A long menu on a fixed header runs past the screen unless navbar-nav-scroll caps it, which starts scrolling at 75vh by default.

Offcanvas panel

The offcanvas panel works as a slide-in drawer with its own header, close button, and scrolling body.

Long menus scroll inside the panel, search and account actions get room, and a backdrop dims the page behind it. Esc closes it by default, and body scrolling is locked while it is open (Bootstrap 5.3 offcanvas docs).

It costs more markup, with a header, title, close button and body to write out. Only one offcanvas can show at a time, and margin or translate cannot go on the .offcanvas element.

The Bootstrap docs disagree with themselves on dark offcanvas panels. The navbar page’s dark example still uses navbar-dark, bg-dark, and text-bg-dark, while the offcanvas page marks that approach deprecated in v5.3.0 in favor of data-bs-theme=”dark”.

Use the attribute on the nav. The offcanvas sits inside the nav, so it inherits the theme.

Start with collapse. Switch to offcanvas the first time the open menu covers more than half the screen.

How to Make a Bootstrap Header Accessible

Start with a skip link. Add an a tag with visually-hidden-focusable and an href pointing at the main content id, placed before the header. Use that class alone, never together with visually-hidden.

The Collapse plugin flips aria-expanded on the toggler for you. If the trigger is not a button, add role=”button”.

Inside a dropdown, an active entry takes aria-current=”true”, because it marks the current item in a set. Page-level links take “page”.

Bootstrap adds cursor-key movement and Esc to close on dropdowns, but no ARIA menu roles. Leave role=”menu” off unless you build the full pattern. An offcanvas panel needs aria-labelledby pointing at its title, and the script adds role=”dialog” itself.

Bootstrap’s components are generic on purpose, so authors often need to add further ARIA roles and attributes. The docs note where.

Text contrast is the last thing to check, meaning the contrast ratio between link text and its background. WCAG 2.2 sets 4.5:1 for normal text and 3:1 for large text, meaning 18 point or 14 point bold (W3C, WCAG 2.2).

Bootstrap’s own sources split on how safe the default palette is. The v5.0.0 migration notes say the framework raised its internal threshold from 3:1 to 4.5:1, yet the accessibility page still warns that some default color pairs fall below 4.5:1, especially on light backgrounds.

Test your pair either way. Disabled links are the one exception, since WCAG sets no contrast requirement for inactive components, and the default disabled color on dark navbars is white at .25 opacity.

The accessibility docs point to Color Contrast Analyser, HTML_CodeSniffer, Deque axe and Microsoft Accessibility Insights for testing. Run one on both the open and closed menu states.

When the Bootstrap Header Breaks

Most broken headers come down to markup written for a different version of Bootstrap. Script problems and layout side effects from scrolling or padding settings cover the rest.

Toggler and dropdown failures

When the toggler or a dropdown does nothing, check these first.

  • The bundle script is missing, or both bootstrap.js and bootstrap.min.js load (the docs say not to include both).
  • Version 4 attributes sit on a v5 page. Bootstrap 5 namespaced them as data-bs-*, so data-toggle and data-target do nothing.
  • The snippet came from MDB, whose data-mdb-* attributes plain Bootstrap ignores.
  • Two collapse wrappers share one id, and the selector finds only the first match.

React, Vue and Angular projects hit a separate problem. Bootstrap’s JavaScript is not fully compatible with them, and both sides may mutate the same element, leaving dropdowns stuck open (Bootstrap 5.3 JavaScript docs).

Keep the CSS and swap the scripts for React Bootstrap or ng-bootstrap. For Vue 3, the docs list BootstrapVueNext, which they mark as alpha as of October 2026.

Version mismatches

Bootstrap 4.6.2, published July 19, 2022, is the last release on the 4.x line (npm registry). Snippets written for it still turn up in header searches.

ItemBootstrap 4Bootstrap 5
Toggler attributesdata-toggle, data-targetdata-bs-toggle, data-bs-target
JavaScript dependencyjQuery, Popper 1.xNo jQuery, Popper 2.x in the bundle
Spacing classesml-auto, mr-automs-auto, me-auto
Active classOn .nav-item or .nav-linkOn .nav-link only
Inner containerOptionalRequired inside the navbar

The usual failure is a mix of columns, like a v4 toggler running on v5 scripts, or ml-auto on a v5 page where the margin does nothing.

Layout side effects

navbar-nav-scroll sets overflow-y: auto, which forces overflow-x to auto as well, so some horizontal content gets cropped (Bootstrap 5.3 navbar docs).

Padding on the .collapse element is a separate trap. The plugin animates height down to 0, so padding there cannot animate cleanly and the docs advise against it. Put the padding on an inner wrapper.

If your custom CSS loses to Bootstrap’s, load your stylesheet after Bootstrap’s and keep selectors specific. A guide to overriding Bootstrap’s default CSS covers the specificity rules.

Fix the version first. Everything else is smaller.

Bootstrap Header FAQ

How do I center the links in a Bootstrap header?

Add mx-auto to the navbar-nav list. The auto margins on both sides place the links in the free space between the brand and any buttons, which is not always the exact center of the page.

Can a Bootstrap header sit transparent over a hero image?

Yes. Add bg-transparent, then lift the navbar out of the flow with position-absolute and w-100, or fixed-top.

Set data-bs-theme=”dark” if the image is dark. The opened mobile menu still needs its own background to stay readable.

Why does the mobile menu stay open after a link click?

The Collapse plugin closes the menu only through its own toggler, and anchor links on a single page do not reload anything. Call hide() on the collapse instance from a click handler on the links. Bootstrap’s methods are asynchronous, so the menu finishes closing after the call returns.

Can the header highlight the current section while scrolling?

Yes, with the Scrollspy plugin. Set data-bs-spy=”scroll” on the scrolling element, point data-bs-target at the nav, and give each link an href that matches a section id.

Since v5.2.0 it uses the Intersection Observer API and no longer needs a relatively positioned parent (Bootstrap migration notes).

How do I change the Bootstrap header height?

The navbar has no fixed height, so padding sets it. Override –bs-navbar-padding-y on the .navbar, or add py-* utilities, and remember that brand size and link line height add to the result.

Does a Bootstrap header work with right-to-left languages?

Yes. Bootstrap 5 renamed directional classes to logical ones (ms-auto, me-auto, start, end), so the same markup mirrors correctly. Load the RTL build of the CSS and add dir=”rtl” to the html element.

Keeping a Bootstrap Header Consistent Through Upgrades

A Bootstrap header stays consistent across every page when one shared template renders it and the framework version is pinned to an exact release.

Start by moving the header markup into one shared partial, which turns a site-wide change into one edit instead of one per page. Pin the CDN path or npm version exactly after that. Replacing deprecated classes before the next minor release comes last.

Pinning carries a cost. The docs’ own CDN examples lock bootstrap@5.3.8 behind an integrity hash, so every patch release needs a manual version bump.

Bootstrap 6 is the next thing to plan around. As of October 2026, the 5.3 docs list v5.3.8 as current and schedule .text-muted for removal in v6.0.0, and v6.0.0-alpha.1 has been on npm since October 8, 2026, so audit deprecated classes before the stable release ships.