Angular — Sticky Header (Scroll-Then-Fix)

Recently I have refactored an old Javascript web application with Angular2, is a minimalistic news aggregator powered by a real-time news search API:

The refactoring process was pretty sleek, once you learn the basic of Angular you quickly gain moment and you progress at an incredible pace.
However in few occasions it required me quite some time to find suitable solutions to implement common UX interactions. In the specific I struggled quite a bit to implement the sticky header behavior (see following animations).

A sticky header, is similar to the iPhone section list header. Every section element has a header that will stick to the top of the screen while scrolling till the current top section is on the screen area. As soon as the current section has been completely scrolled out of the following section the header will replace the current one and stick to the top. Its kind of difficult to explain therefore I am attaching a second animation to better illustrate the sticky header concept:


Upon request I created a live demo of the concept presented in this article.
It took me quite a while to find the time for it, so even though this article is referring to Angular 2 the demo actually runs on Angular 4.

Sticky Header Demo


Among the many API that Angular2 offers, I took particularly advantage of the inter-component communication @Input @Output to implement the UX interaction.

The beauty of this solution is it’s simplicity, with a few lines of codes and a very minimal architecture we can obtain a pretty advanced UI interaction and provide great user experience.
The main concept to achieve the desired behavior is to leverage on the HostListener and EventEmitter Angular2's API in conjunction to a parent component (container) and a list of child components (sections).

While scrolling the parent container will compute which of its child sections are currently on the screen and which have been scrolled out of the page. Also the parent component will compute which is his top most child section still visible in the screen and update the sticky header title accordingly.

Section components

Multiple sections are placed inside a parent container. Once the page is rendered or resized every section informs the parent container about its new y-offset to the page top. This is done by emitting an event on ngOnInit and on window resize. To capture the on window resize event the HostListener API is used.

Container Component

Similarly the sections the parent container keeps track to his offset to the top of the page as well. Doing so will allow the parent container to compute the absolute position on the screen of every child sections. The parent component will also listen to the scroll event. Anytime the page starts to scroll the parent component will determine witch section is currently getting out of the screen (being scrolled out) and set the sticky header title to the section name.


In terms of styling and page structure the main trick is a position a fixed header element inside the parent container meant to overly the section header. Both headers should be styled identically in this example with a H2 element. Once the first section will go off screen the parent container will display the fixed position header and overly the ones of the sections.


For the sake of simplicity the presented implementation has not been optimized.
Instead of running a for loop over all section till the one top most out of screen has been found, consider doing a binary search based on the section offset and the current scroll position.

Furthermore the positions Array could be replaced with an SortedSet to allow a quick replacement of each section position in case of screen resize.


The main inspiration for this Angular 2 sticky header solution was taken from Chris Coyier’s article:

Enjoyed the article? You may consider clapping it to recommend it to other interested readers!

Like what you read? Give Elia Palme a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.