Bootstrap 5 Scrollspy
Use a scrollable region and matching anchors so the current visual link can follow reading position.
How it works
Scrollspy observes content sections and updates matching navigation state. It does not scroll keyboard focus into the active link or replace a meaningful page outline. The scrollable root, target navigation and section anchors must agree. A bounded region needs enough overflow to scroll, and its focusability can make keyboard scrolling available. Intersection behaviour depends on layout and observer settings, so test actual movement rather than assigning an active class in a screenshot.
Run and inspect
Save the complete document as index.html in a separate lab folder. Place Bootstrap 5.3.8 CSS and the matching JavaScript bundle beside it. Open the file in a normal browser. A separate local static server is optional; no database or PHP execution is required. Keep the Bootstrap licence and bundled Popper licence with redistributed assets.
Download this complete HTML source.
This example needs the complete local setup with the Bootstrap JavaScript bundle. The restricted CSS playground does not reproduce this example’s full contract.
Example
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 5 Reflect the Visible Section Without Moving Focus</title>
<link rel="stylesheet" href="bootstrap.min.css">
<style>
#spy-region { height: 12rem; overflow-y: auto; position: relative; padding: 1rem; border: 1px solid var(--bs-border-color); } #spy-region section { min-height: 18rem; }
</style>
</head>
<body>
<main class="container py-4">
<h1 class="h3 mb-4">Repair day</h1>
<nav id="spy-links" class="nav nav-pills gap-2 mb-3" aria-label="Reading sections"><a id="spy-first" class="nav-link" href="#spy-sessions">Sessions</a><a id="spy-last" class="nav-link" href="#spy-arrival">Arrival</a></nav><div id="spy-region" data-bs-spy="scroll" data-bs-target="#spy-links" data-bs-root-margin="0px 0px -20%" tabindex="0" aria-label="Scrollable event information"><section id="spy-sessions"><h2 class="h5">Sessions</h2><p>Paper and fabric practice use simple sample materials.</p></section><section id="spy-arrival"><h2 class="h5">Arrival</h2><p>Use the east entrance and leave space at the doorway.</p></section></div>
</main>
<script src="bootstrap.bundle.min.js"></script>
</body>
</html>
Expected result
Scrolling the bounded region to its last section makes Arrival the active visual navigation item without forcing focus away from the reading region.
The anchors point to real section IDs, while data-bs-target names the navigation to update. The region has a deliberate height and overflow policy in the lab CSS. On a full page, account for sticky headers and real content height before choosing observer margins. Dynamically changed section geometry may require the plugin’s refresh lifecycle.
Check Bootstrap’s official 5.3 documentation for component contracts and version details.