Since 15.1.0

Scrollspy service and set of directives help to watch scroll position changes of the document or a specific container and get notified when a part of it is scrolled into or out of the viewport.

The core scrollspy implementation is a NgbScrollSpyService that is based on an IntersectionObserver. You can see the example of the service working on this very page to highlight which documentation section is currently active.

You should at least specify which container you'd like to spy on and which sections (fragments) inside this container should be watched. Fragments are identified by unique id attributes.

For example, if you want to watch for the document scroll changes, you need to do at least the following:

You can also pass multiple options when starting a service. For example, you can set a specific container element instead of the whole document, configure the intersection observer and change scrolling behavior.

You can use the service together with the routerLink directive and its [fragment] input, or you can force the scrollspy to get to a specific fragment via the .scrollTo() method.

The directive will help you to setup the scrollspy service instance on a specific container. It is merely a syntactic sugar around the service that will start and add fragments automatically, as well as clean everything up when host component is destroyed.

It will look something like this:

Please see and the demos and NgbScrollSpy API for all available inputs and outputs.

There are also two helper directives: NgbScrollSpyMenu and NgbScrollSpyItem. They will highlight the active item in a menu, nav or any custom list.

Individual items

NgbScrollSpyItem directive either gets the nearest scrollspy from the DI or uses the direct reference. It adds and removes .active class dynamically based on the current scrollspy state.

It has also several convenient ways of referencing related scrollspies and fragments:

For more details, please see the related remo

Hierarchical menus

In case of multiple nesting levels, you might want to highlight the whole branch of the menu and not only a single item. For this purpose, you can use the NgbScrollSpyMenu directive on a container with items.

It this case you might reference scrollspy only once at the menu level, or not reference at all if it is available via DI.

For more details, please see the related remo

If you want to customize the IntersectionObserver you can pass rootMargin and threshold options when starting the service.

If you don't like the default scrollspy behavior or would like to process intersection observer events on your own, you can completely override the algorithm by providing your own implementation function via the [processChanges]="myCustomProcess" input or set it directly via the service start options.

For example, default scrollspy implementation doesn't allow for gaps in-between items, ex. if you're in-between fragments 'one' and 'two' ('one' is not visible anymore and 'two' is not visible yet), we'll still mark item 'one' as active.

If you provide your own function, you'll get the list of the intersection observer entries and you can process them as you wish. You can use the current scrollspy state and it's up to you to call the provided changeActive() method when it's time to change the active fragment. You can also use the context that is persisted across the calls.