DEV Community

Anirban Mukherjee
Anirban Mukherjee

Posted on • Updated on • Originally published at theangularpath.anirbanblogs.com

Implement scroll-to-top in Angular

@angular/cli: 15.2.8
Source: GitHub

In this article I would like to talk about an often-used feature on a user-centric application - the scroll-to-top button for allowing a user to quickly scroll to the top of the page, without having to use the mouse. The end result would be something like this:

preview


Let's break up this implementation into 3 steps:

✔️ Set up the scroll-to-top button (with some nice styling).
✔️ Determine when the button should be displayed.
✔️ Scroll to the top of the page on clicking the button.


Set up the scroll-to-top button:

I have used @angular/material for some easy styling. In order to display the button fixed to the bottom-right corner of the page (and some nice hover effects with opacity), I have used the below properties on the :host -

scroll.component.scss


Determine when the button should be displayed:

This is an interesting section. To begin with, we need to set up an Observable on the scroll event of the DOCUMENT. You may directly access the document object, or you may use an InjectionToken<Document>, provided by angular.

This observable starts emitting values as soon as the user starts to scroll up or down. Now we are not really interested in the actual scroll event, but we would like to check something important every time the scroll event is fired - and that is the scroll position. Angular makes this quite simple with the ViewportScroller service from @angular/common package. This service has few useful methods, and I am going to use two of them - getScrollPosition and scrollToPosition.

list.component.ts

The getScrollPosition method returns an array of 2 numbers - the X and Y coordinate. I check if the Y coordinate is more than 0 (which means the user has scrolled down) and I enable the scroll-to-top button.


Scroll to the top of the page on clicking the button:

For this last part, I make use of the scrollToPosition method, which again takes in the X and Y coordinates, and I scroll to [0, 0].

list.component.ts


UPDATE

The source code has been updated to angular 15, with standalone components. The main branch contains the updated syntax of angular 15. Refer to the legacy branch to view the old syntax of angular 13.

Cheers :-)
Anirban Mukherjee

Top comments (6)

Collapse
 
rvwilliams88 profile image
rvwilliams88

OK I've solved the problem. Remove DOCUMENT and replace 'this.document' with 'window'. With that change it works great! Thanks for the article.

Collapse
 
anirbmuk profile image
Anirban Mukherjee

@rvwilliams88 sorry for a late reply. Unfortunately none of my machines has a v15 set up, so I can't really say what's wrong with the original approach. But if I had to give you a work-around then I would have done it the way you have. Nice that you figured it out yourself. But as always be careful while using the window object. Protect it using the isPlatformBrowser check as it may break on server-side rendering.

Collapse
 
rvwilliams88 profile image
rvwilliams88

This doesn't work for me. I'm on Angular 15. In showScroll$, this.document is marked as an error with the message
Property 'document' is used before its initialization.ts(2729)
viewer.component.ts(35, 15): 'document' is declared here.
Line 35 includes
@Inject(DOCUMENT) private readonly document: Document,

I'm not able to find a way around this. Can you help?

Collapse
 
jwess profile image
Joel

Can you please explain the benefit of putting the actual scrolling logic outside the ScrollComponent?

Collapse
 
anirbmuk profile image
Anirban Mukherjee

No honestly there isn't. It is your choice tbh. You can choose to consider the scroll-component as a specific button, which emits an event on click. Or you can choose to put all scroll related logic inside the component.

I have done both, depending on whether I am creating the component as part of a library or as a standalone component in a monorepo.

Collapse
 
artursbuls profile image
ArtursBuls

Works fine, without any issues on:
"@angular/core": "^16.1.0",