What Is a Bootstrap Navbar?
It’s a piece of the Bootstrap framework that lays out its children with flexbox. You pick the breakpoint where it collapses, and the Collapse plugin does the hiding and showing.
The official docs name these parts:
- .navbar-brand, the site or project name (an anchor works best)
- .navbar-nav, the link group, built on the .nav component and able to hold dropdowns
- .navbar-toggler, the button that opens and closes collapsed content
- flex and spacing utilities for forms and action buttons
- .navbar-text for vertically centered strings of text
- .collapse.navbar-collapse, which groups and hides content below a breakpoint
- .navbar-nav-scroll, which adds a max-height and vertical scrolling inside collapsed menus
Navbars and their contents are fluid by default. Immediate children of .navbar use flex layout with justify-content: space-between, and the link group grows to fill whatever horizontal space is left.
Since it usually serves as the navigation of a site, assistive technology should read it as a landmark region. Use a nav element, or role=”navigation” on a generic div.
The link for the current page gets aria-current=”page” (Bootstrap documentation).
How to Build a Basic Responsive Bootstrap Navbar
The Bootstrap CSS file and bootstrap.bundle.min.js come first. After that it’s a chain of markup: a wrapper, a container, the brand, the toggler, the collapse block and the link list.
- Load bootstrap.min.css from the jsDelivr CDN in the head of the page.
- Load bootstrap.bundle.min.js from jsDelivr after the page content.
- Add a nav element with the classes navbar, navbar-expand-lg and bg-body-tertiary.
- Put a container-fluid div inside it. Swap in container or a responsive container such as container-md if you want to limit the width.
- Add an anchor with navbar-brand, then a button with navbar-toggler, data-bs-toggle=”collapse” and a data-bs-target that points to the collapse block id. A span with navbar-toggler-icon goes inside the button.
- Add a div with collapse, navbar-collapse and that id. Inside it goes a ul.navbar-nav with li.nav-item and a.nav-link children, and the link for the current page gets active and aria-current=”page”.
The result is plain HTML markup, and the default look needs no custom CSS.
Don’t skip the container. Bootstrap 5 treats it as required, and the v5.0.0 migration notes list that as a breaking change from Bootstrap 4.
In Bootstrap 5 the plugins were rewritten in vanilla JavaScript, so no jQuery gets loaded. Version 4.6 works differently. Its bundle includes Popper but not jQuery, so jQuery has to load first (Bootstrap 4.6 documentation).
The bundle matters most for dropdowns. They need Popper, and bootstrap.bundle.min.js already contains it, while the separate bootstrap.min.js file needs Popper loaded before it.
Pin the CDN URL to a specific release. The docs footer lists v5.3.8 as current as of October 2026, and the introduction page carries the full tags with integrity hashes to copy.
How the Navbar-Expand Classes Set the Collapse Point
The navbar-expand-{breakpoint} class sets the viewport width where the navbar stops collapsing and lays its links out in one row. Below that width the toggler shows and the .navbar-collapse block stays hidden.
Each class maps to a min-width media query from Bootstrap’s grid breakpoints. The layout is mobile-first, so the rule applies from that width upward (Bootstrap documentation):
- navbar-expand-sm: 576px and up
- navbar-expand-md: 768px and up
- navbar-expand-lg: 992px and up
- navbar-expand-xl: 1200px and up
- navbar-expand-xxl: 1400px and up
The xxl tier arrived with v5.0.0, so navbar-expand-xxl does not exist in Bootstrap 4.
If you want a navbar that never collapses, add .navbar-expand with no suffix. For one that always collapses, leave out every .navbar-expand class.
The toggler only works when its attributes line up with the collapse block. data-bs-toggle=”collapse” hands the button to the Collapse plugin, and data-bs-target=”#id” points to the id of the .navbar-collapse block. aria-controls repeats that id for assistive technology. aria-expanded=”false” sets the starting closed state, and aria-label=”Toggle navigation” gives the icon-only button a name.
Those ARIA attributes matter because the hamburger icon has no visible text, so a screen reader has nothing else to announce.
The plugin matches the data-bs-target value to the id. A typo in either one leaves the button inert, and nothing in the console will tell you why.
Placed after the brand, the toggler sits at the far right. Reverse the markup order and it moves to the left.
The collapse animation follows the prefers-reduced-motion media query, per the Bootstrap docs.
Navbar Colors, Dark Mode and Version Differences
In Bootstrap 5.3, a navbar takes its light or dark scheme from data-bs-theme on the .navbar element, and a bg-* utility sets the background.
| Version | Light scheme | Dark scheme | Toggler attribute |
|---|
| Bootstrap 4.x | navbar-light bg-light | navbar-dark bg-dark | data-toggle |
| 5.0 to 5.1 | navbar-light bg-light | navbar-dark bg-dark | data-bs-toggle |
| 5.2 | bg-light (navbar-light deprecated) | navbar-dark bg-dark | data-bs-toggle |
| 5.3 | bg-body-tertiary | data-bs-theme=”dark” (navbar-dark deprecated) | data-bs-toggle |
Light and dark schemes in 5.3
Bootstrap 5.3.0 reached its stable release on May 30, 2023 (Bootstrap Blog). The data-bs-theme attribute had first shown up in 5.3.0-alpha1 in December 2022.
On a navbar, data-bs-theme=”dark” replaces the deprecated navbar-dark class. It also works on any parent element, so a single value on the html element switches the whole page.
The scheme only sets text colors. The background still comes from a bg-* utility. A neutral dark bar uses bg-dark with border-bottom and border-body. For a colored bar, put bg-primary together with data-bs-theme=”dark”. A pale tint is the odd one out, with a custom background color and data-bs-theme=”light”.
A custom background shifts the contrast the scheme was tuned for, so check the color contrast between link text and the new color before shipping.
One wrinkle in the official docs. When a GitHub issue (#40566) was filed on the Bootstrap repository, the navbar page showed the new data-bs-theme code while the dropdown page still used the old dark variant class. Copy from different component pages and you can end up with both generations in one project.
Renamed classes and attributes from Bootstrap 4
jQuery was dropped in v5.0.0, and Popper moved from v1.x to v2.x (Bootstrap migration guide). Plugin attributes are now namespaced, so data-toggle becomes data-bs-toggle and data-target becomes data-bs-target.
The spacing utilities changed too. .ml-* and .mr-* became .ms-* and .me-*, which is why mr-auto does nothing in a v5 navbar. And .active can no longer sit on a .nav-item. It goes directly on the .nav-link.
A Bootstrap 4 snippet pasted into a v5 page loses its toggle first, because the old data-toggle attribute is no longer read.
CSS and Sass variables
Bootstrap v5.2.0 moved the navbar onto CSS variables, so colors and spacing change without recompiling Sass.
The v5.3.8 source defines 20 –bs-navbar-* variables on .navbar, from –bs-navbar-padding-x to –bs-navbar-toggler-transition. –bs-navbar-color sets link color and –bs-navbar-hover-color sets the hover state.
If you compile Sass, change the $navbar-* variables before compiling, such as $navbar-padding-y (default $spacer * .5) and $navbar-brand-font-size.
Plain CSS overrides work too, and the approach in overriding Bootstrap’s default CSS applies to the navbar like any other component.
Navbar Placement: Fixed, Sticky and Scrollable
Placement comes down to fixed-top, fixed-bottom, sticky-top and sticky-bottom. Fixed pins the navbar to the edge of the browser viewport. Sticky lets it scroll with the page until it reaches that edge.
A fixed navbar leaves the normal document flow, so it overlaps page content and stays visible at all times. The docs say you may need custom CSS, such as padding-top on the body, to prevent that overlap.
A sticky navbar keeps its place in the document flow and reserves its own space. It scrolls with the page, then stays put once it hits the edge.
I’d default to sticky. Reach for fixed only when the navbar has to overlay content from the first pixel, such as a transparent bar over a hero section.
That pattern is usually called sticky navigation, and in Bootstrap it takes a single class, sticky-top.
Bootstrap’s z-index scale puts fixed elements at 1030 and sticky elements at 1020, according to the docs. They also warn that if you change one value you likely need to change them all.
Long menus are a separate problem. Add .navbar-nav-scroll to a .navbar-nav and the menu scrolls inside the collapsed navbar instead of running off the screen. Scrolling starts at 75vh by default.
The docs prose names –bs-navbar-height as the override, but the v5.3.8 source and the docs’ own example both use –bs-scroll-height. Go with the second one.
There’s a drawback that comes from overflow. Setting overflow-y to auto also turns overflow-x into auto, which crops some horizontal content. Above the expand breakpoint the class sets overflow back to visible.
Adding Links, Dropdowns, Forms and Icons
Links, dropdowns, forms and icons all sit inside .navbar-collapse, and Bootstrap’s flex and spacing utilities decide where each group lands.
Active link and Scrollspy
A plain active state is manual. Scrollspy automates it on single-page layouts by toggling .active on any anchor whose target id has scrolled into view.
data-bs-spy=”scroll” and data-bs-target=”#navId” go on the scrollable element, which can be the body. Each link needs a resolvable id target, or the plugin ignores it. If the container holds no focusable element, add tabindex=”0″ so keyboard users can reach it.
rootMargin sets the trigger zone, and data-bs-smooth-scroll=”true” animates link clicks.
Items inside a navbar dropdown highlight too, and an active nested nav marks its parents active.
Scrollspy has run on the Intersection Observer API since v5.2.0. The offset option is deprecated, still parsed into rootMargin, and scheduled for removal in v6, yet one of the v5.3 docs examples still sets data-bs-offset.
Dropdown menus
A navbar dropdown needs a wrapper. Nest a .nav-link.dropdown-toggle and a .dropdown-menu inside a .nav-item.dropdown, because the docs require separate elements for positioning.
The toggle takes data-bs-toggle=”dropdown” and aria-expanded=”false”, and role=”button” is recommended when it’s an anchor. The menu itself is filled with .dropdown-item, .dropdown-divider and .dropdown-header. If a menu sits near the right edge, .dropdown-menu-end right-aligns it.
Items, dividers and headers behave as in a standalone Bootstrap dropdown. Arrow keys move through the .dropdown-item elements and Esc closes the menu.
Bootstrap adds no ARIA menu roles, so any role and aria attributes beyond the basics are yours to write.
Inside the collapsed navbar a dropdown opens inline (position: static). Above the expand breakpoint it floats as an absolutely positioned menu, per the v5.3.8 source.
Alignment with flex utilities
Alignment is a margin question, not a navbar class.
me-auto on .navbar-nav keeps the links left and pushes whatever follows, such as a form, to the right. ms-auto moves the links themselves to the right. mx-auto centers them.
The docs’ own examples add mb-2 mb-lg-0 so the stacked links get bottom spacing only while collapsed.
Forms and icons
A search form is a form with d-flex and role=”search”, an input with form-control and me-2, and a button with a btn variant. When the navbar is mostly a form, the form itself can act as the container.
For icons, the Bootstrap icon set is the project’s own library. The .icon-link helper in 5.3 places and aligns an icon beside link text.
Logos follow a similar pattern. Put an img inside .navbar-brand, with d-inline-block and align-text-top to line it up next to text.
Collapse or Offcanvas for the Mobile Menu?
For a short list of links, collapse is the default and usually enough. Offcanvas earns its place when the menu is long, nested, or just easier to use as a panel over the page.
| Attribute | Collapse | Offcanvas |
|---|
| Layout effect | Pushes page content down as its height animates | Slides over the page from an edge, with a backdrop |
| Page scroll | Page scrolls as usual | Body scroll is off unless data-bs-scroll=”true” |
| Ways to close | Toggler click | Close button, backdrop click or Esc |
| Default width | Full navbar width | 400px (Sass default) |
| Toggle attribute | data-bs-toggle=”collapse” | data-bs-toggle=”offcanvas” |
Offcanvas turns the mobile menu into a drawer, an overlay panel that enters from the left, right, top or bottom edge. Navbars gained support for it in v5.1.0, and the panel sits at z-index 1045, above fixed navbars.
The hamburger menu button stays, but the markup around it changes in a few places.
- The toggler swaps the collapse attributes for data-bs-toggle=”offcanvas” and a data-bs-target pointing at the panel id.
- The panel is a div with offcanvas, a placement class such as offcanvas-end, tabindex=”-1″ and aria-labelledby.
- Its header is .offcanvas-header with an .offcanvas-title and a btn-close carrying data-bs-dismiss=”offcanvas”.
- .offcanvas-body holds the ul.navbar-nav and any search form.
- Keep navbar-expand-lg and the panel becomes a normal navbar from lg up. Drop the class and you get a drawer at every width.
By default the panel closes on a backdrop click or Esc, locks body scrolling while open, and allows one offcanvas at a time.
Treat it as a modal dialog and point aria-labelledby at the title, since JavaScript adds role=”dialog” itself. A dismiss button outside the panel works but does not match the ARIA dialog pattern, per the docs.
The Bootstrap docs show two approaches to dark drawers, and they disagree. The navbar page’s example still stacks navbar-dark, bg-dark, text-bg-dark, btn-close-white and dropdown-menu-dark, while the offcanvas page marks that approach deprecated in v5.3.0 in favor of data-bs-theme=”dark”.
In a 5.3 project, use the attribute. The navbar page also warns that offcanvas text can turn illegible in a dark navbar without a dark background.
Why a Bootstrap Navbar Breaks and How to Fix It
Most navbar failures trace back to how the plugins read their attributes.
| Symptom | Cause | Fix |
|---|
| Toggler does nothing | JS bundle not loaded, or data-toggle used instead of data-bs-toggle | Load bootstrap.bundle.min.js and use the data-bs-* attributes |
| Toggler still does nothing | data-bs-target and the collapse id differ | Make both strings identical |
| Menu never collapses, or never expands | .navbar-expand with no suffix, or no expand class at all | Use one navbar-expand-{breakpoint} class on .navbar |
| Dropdown does not open | data-bs-toggle=”dropdown” missing, or plugin JavaScript not loaded | Add the attribute and load the bundle |
| Menu stays open after a link click | An in-page link does not reload the page, so nothing closes the collapse | Call hide on the Collapse instance in a click handler |
Toggler and collapse failures
The Collapse plugin reads data-bs-toggle and data-bs-target. Bootstrap 4 attributes get skipped.
Padding on .navbar-collapse causes its own trouble. The docs rule it out on a .collapse element because of how CSS handles height animation. Wrap the content in an inner element and pad that instead.
For the menu that stays open after a click, call bootstrap.Collapse.getOrCreateInstance(el, { toggle: false }).hide() in the link’s click handler.
The toggle option defaults to true, so a fresh instance built with defaults toggles the element on creation. Methods are also asynchronous, and a call made during a transition is ignored.
Dropdown failures
The dropdown documentation adds a qualifier to the Popper requirement. Popper is not used to position dropdowns in navbars, because dynamic positioning is not required there.
The same page still says to load Popper or use the bundle, so the bundle stays the safe choice.
- data-bs-toggle=”dropdown” is also relied on to close dropdowns at the application level, so always include it
- A dropdown closes on clicks inside or outside the menu by default, so a form that should stay open needs data-bs-auto-close=”outside”
- data-bs-display=”static” is not needed in a navbar
Where the navbar stops being enough
Bootstrap dropdowns open on click, never on hover. The docs call that an intentional design decision.
The v5.3 docs describe no submenu pattern either. An answer recorded in the Bootstrap 4 issue tracker (#21026, October 2016) says nested dropdowns have not been supported since v3.
Hover menus and multilevel submenus therefore mean custom code, such as pure CSS dropdown menus or script-driven behavior layered on the plugin.
If those patterns are central to the design, weigh the patching cost before committing to the Bootstrap navbar.
Bootstrap Navbar FAQ
Is a navbar the same thing as a nav in Bootstrap?
No. The .nav component is the base for link lists such as tabs and pills, while .navbar is a header wrapper with its own .navbar-nav modifier and toggler behavior.
Navbar links reuse .nav-link, but .navbar-nav sets its own flex layout, so the .nav class is not needed (v5.3.8 source).
How can I make a Bootstrap navbar transparent?
Leave off the bg-* class. The .navbar rule sets no background color of its own, so the page shows through, and bg-transparent does the same explicitly.
Over a dark hero image, add data-bs-theme=”dark” so the link text turns light.
How do I change the hamburger icon color?
Text color utilities won’t touch it, because the toggler icon is an SVG background image.
Override –bs-navbar-toggler-icon-bg with your own SVG, or switch the navbar scheme with data-bs-theme, which swaps in the stored dark icon. The border color has its own variable, –bs-navbar-toggler-border-color.
Which setting controls the height of a navbar?
Vertical padding does. Set –bs-navbar-padding-y on the .navbar, or add a py-* utility class.
The brand and the links carry their own padding as well, so a tall logo inside .navbar-brand stretches the bar too.
Which Bootstrap Navbar Setup Fits a New Project?
A new project should start on the v5.3 pattern. That means bg-body-tertiary for the background, data-bs-theme for color, and one navbar-expand-lg class with the bundled JavaScript.
Wire it in this order, since each step depends on the one before:
- Breakpoint class
- Toggler id and data-bs-target pair
- Close handler for in-page links
The breakpoint comes first because it decides which layout every later rule targets. The close handler only matters on single-page layouts, since a full page load already resets the menu.
This position was verified against v5.3.8 in October 2026. That source schedules navbar-light for removal in v6.0.0, so a Bootstrap 6 release would change the class list.
The same data-bs-* attributes carry over to other Bootstrap components, the natural next area to learn.