Reactive Sticky Header in Angular

Show And Hide Sticky Header Based on the Scroll Direction

Tomasz Kula
Netanel Basal

--

In this article, we will explore a common UI pattern - sticky header that is displayed or hidden based on the direction of the scroll. We will implement this with RxJS and Angular Animations.

First, we get a handle on the scroll stream with the use of fromEvent observable creator.

fromEvent

Creates an observable sequence by adding an event listener to the matching DOMElement

To get better performance, we throttle the event stream with the use of the throttleTime operator. We keep the throttle value low as we don’t want to make the showing and hiding of the header to feel unresponsive.

throttleTime

Returns an Observable that emits only the first item emitted by the source Observable during sequential time windows of a specified duration.

Next, we map the window object to the pageYOffset, which returns the number of pixels the document is currently scrolled along the vertical axis.

Since we’re interested in the direction of the scrolling, we must compare the subsequent changes to the pageYOffset as the user scrolls.

To achieve this, we group the values emitted by the scroll stream in pairs with the use of thepairwise operator.

pairwise

Triggers on the second and subsequent triggerings of the input observable. The Nth triggering of the input observable passes the arguments from the N-1th and Nth triggering as a pair.

Next, we compare the pixel values in each pair. If the second value is lower than the first, the user is scrolling up. Otherwise, he is scrolling down.

Notice that there are a lot of repeated values being emitted. Since we are only interested in the changes of the direction, we can remove the repeated events with the use of the distinctUntilChanged operator.

distinctUntilChanged

Returns an observable sequence that contains only distinct contiguous elements

Finally, we create two streams: scrollUp$ and scrollDown$ with the use of the filter operator. We also apply the share operator to the scroll$ stream, to avoid creating multiple subscriptions.

share

Returns an observable sequence that shares a single subscription to the underlying sequence.

Now it’s time to update the view based on the values emitted by the scrollUp$ and scrollDown$ streams. For this, we will use @angular/animations.

First, we consume the streams by setting the value of theisVisible flag. We will use this flag to create the animation trigger.

We want the header to be visible when scrolling up, and to be hidden when scrolling down, so we update the flag accordingly.

Next, we create a host binding for the @toggle animation trigger. It maps the isVisibility flag to the desired VisibilityState. We will create the animation in the next step.

Finally, we implement the animation. We use toggle as the animation trigger and VisibilityState to describe the possible states of the header. The state functions update the header’s opacity and transform CSS properties with the use of the style function.

And that’s it. We have a working reactive sticky header.

Note On Performance

You might consider running the above code outside the Angular Zone to prevent the change detection from being fired too frequently. You can read more about NgZone in the official documentation.

Complete example:

If you like the content, please clap 👏👏👏

To read more about Angular, follow me on Medium or Twitter.

--

--