Skip to content

Bootstrap Scrollspy

The Scrollspy plugin is used to automatically update links in a navigation list based on the current scroll position on the page. This is great for single-page websites or documentation pages where you want to highlight the active section in the navigation.

As you scroll the page, the active class is added to or removed from navigation items, visually indicating which section is currently in view.

The following example shows how to create a basic Scrollspy with a fixed top navigation bar:

<!-- The navigation bar (navbar) -->
<nav id="navbar-example" class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top px-3">
<a class="navbar-brand" href="#">My Page</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="#section1">Section 1</a></li>
<li class="nav-item"><a class="nav-link" href="#section2">Section 2</a></li>
<li class="nav-item"><a class="nav-link" href="#section3">Section 3</a></li>
</ul>
</div>
</nav>
<!-- The scrollable area (e.g., the body or a specific div) -->
<!-- Add data-bs-spy, data-bs-target, data-bs-offset, and tabindex (if not body) -->
<div data-bs-spy="scroll" data-bs-target="#navbar-example" data-bs-offset="70" tabindex="0" style="padding-top: 56px;">
<!-- Note: padding-top on scrollable area should accommodate fixed navbar height -->
<div id="section1" style="height: 500px; background-color: #f0f0f0; padding: 20px;">
<h2>Section 1</h2>
<p>Content for section 1... Try to scroll this page and watch the navigation bar!</p>
</div>
<div id="section2" style="height: 500px; background-color: #e0e0e0; padding: 20px;">
<h2>Section 2</h2>
<p>Content for section 2...</p>
</div>
<div id="section3" style="height: 500px; background-color: #d0d0d0; padding: 20px;">
<h2>Section 3</h2>
<p>Content for section 3...</p>
</div>
</div>
<!--
Important: Scrollspy requires JavaScript. Ensure Bootstrap's JS (bootstrap.bundle.min.js or scrollspy.js + dependencies) is included.
The example above uses inline styles for height and background for clarity; in a real project, use CSS classes.
-->
  • Add data-bs-spy="scroll" to the element that serves as the scrollable area. Often, this is the <body> element, but it can be any scrollable <div>.
  • If the scrollable area is not the <body>, it must have a height set and overflow-y: scroll; for scrolling to occur within it. It also needs tabindex="0" to be focusable for keyboard navigation.
  • Add the data-bs-target attribute with a value that is the ID or class name of the navigation bar (e.g., data-bs-target="#navbar-example" or data-bs-target=".navbar"). This links the scrollable area to the navigation component.
  • The href attributes of the links inside the navigation bar (e.g., <a class="nav-link" href="#section1">) must match the id attributes of the sections in the scrollable area (e.g., <div id="section1">).
  • The optional data-bs-offset attribute (e.g., data-bs-offset="70") specifies the number of pixels to offset from the top when calculating the scroll position. This is crucial when using a fixed/sticky navigation bar, to ensure the correct section is highlighted when its top aligns with the bottom of the navbar, not the very top of the viewport.
  • CSS position: relative; Requirement: The element with data-bs-spy="scroll" (if it’s not the <body>) must have position: relative; in its CSS for Scrollspy to work correctly.

Practical Application: Ideal for single-page applications, landing pages, or documentation sites where navigation helps users jump between content sections and see their current location.

Common Obstacle: Incorrect data-bs-offset value, leading to highlighting the wrong section or highlighting too early/late. This value usually needs to be adjusted to match the height of any fixed/sticky top navigation.

Tip: Scrollspy is initialized automatically via the data-bs-spy attribute. You can also initialize it programmatically using JavaScript: new bootstrap.ScrollSpy(document.body, { target: '#navbar-example', offset: 70 }).

Scrollspy with a Vertical Navigation Menu (e.g., Nav Pills)

Section titled “Scrollspy with a Vertical Navigation Menu (e.g., Nav Pills)”

Scrollspy works equally well with vertical navigation menus. The principles are the same.

In this example, we use a Bootstrap Grid layout with a vertical navigation (.nav-pills.flex-column) in one column and the scrollable content in another. The <body> itself is the scrollable area.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vertical Scrollspy Example</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { position: relative; /* Required for Scrollspy on body */ }
#myScrollspy { position: sticky; top: 20px; /* Make nav sticky */ }
.content-section { height: 400px; padding: 20px; margin-bottom: 20px; border: 1px solid #ccc; }
</style>
</head>
<body data-bs-spy="scroll" data-bs-target="#myScrollspy" data-bs-offset="20">
<div class="container mt-3">
<div class="row">
<nav class="col-sm-3 col-md-2" id="myScrollspy">
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a class="nav-link" href="#contentSection1">Section 1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contentSection2">Section 2</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contentSection3">Section 3</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#contentSection4">Section 4</a></li>
<li><a class="dropdown-item" href="#contentSection5">Section 5</a></li>
</ul>
</li>
</ul>
</nav>
<div class="col-sm-9 col-md-10">
<div id="contentSection1" class="content-section bg-light">
<h4>Section 1</h4>
<p>Content for section 1...</p>
</div>
<div id="contentSection2" class="content-section bg-light">
<h4>Section 2</h4>
<p>Content for section 2...</p>
</div>
<div id="contentSection3" class="content-section bg-light">
<h4>Section 3</h4>
<p>Content for section 3...</p>
</div>
<div id="contentSection4" class="content-section bg-light">
<h4>Section 4 (from dropdown)</h4>
<p>Content for section 4...</p>
</div>
<div id="contentSection5" class="content-section bg-light">
<h4>Section 5 (from dropdown)</h4>
<p>Content for section 5...</p>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
<!-- Further Reading: For all options, methods, and events, check the official Bootstrap Scrollspy documentation: https://getbootstrap.com/docs/5.3/components/scrollspy/ -->