Sleek and interactive scroll bar using Angular directive

Building a re-usable custom scroll bar

Barik Jyoti
Webtips

--

In this article, we will learn to customize the browser’s default scroll bar with an elegant and interactive custom scroll bar using Angular directive.

The default scroll bar on a div with over-flowing content appears below.

Div with default scroller

The scroll bar above is intrusive and prominent. For modern web apps, we would definitely want something subtle to go with the design philosophy and color scheme of the app.

We will strive to build a customizable and reusable solution using Angular directive and some custom CSS. The directive can be used across the application.

The final appearance will be as below.

Div with custom scroller
Div with custom scroller — at rest

Notice that at rest, the scroll bar is subdued, almost seamlessly integrated with the container’s overall design and color scheme. However, when the user interacts with it, it expands and lets the user scroll without searching for it.

Div with custom scroller — active

Let’s put on our developer hat and get this done. 👷

The app.component.html houses a div with some random text in it. The div is styled with custom CSS via the container class so as to get the over-flow effect.

Notice the attribute directive custom-scroll applied to the div element. Using this directive we inject the desired behavior into the hosting element. We also use this directive to listen and react to user actions on the host element to provide interactivity to the custom scroller.

For an in-depth understanding of building custom directives, please check the official guide.

Next, let’s have a look at the directive’s code.

Notice the imports from the core library.

ElementRef provides a reference to the underlying HTML element on which the directive is applied. This enables us to modify element behavior at runtime, by injecting styles and classes.

HostListener provides the ability to subscribe to the DOM events on the hosting element.

Using the @HostListener() decorator the directive is subscribing to the mousemove event on the hosting element. The event data, mouseEvent, is passed to the handler method applyCustomScroll().

The logic in applyCustomScroll() method is quite simple.

Using JavaScript’s getBoundingClientRect() method, we are getting the host element’s position relative to the viewport. From mouseEvent data, the x position of the mouse pointer is fetched using its clientX property. Then this data is used to conditionally apply or remove a CSS class custom-scroll-vertical-hover to the host element. Notice that 10 is subtracted from the host element’s right edge which will ultimately be the size of the scrollbar.

What remains now is to apply necessary CSS to the class custom-scroll-vertical-hover

The above styles are included in the global styles.css file so that the directive custom-scroll can be applied on any container in the application that needs similar behavior.

Essentially, we are overriding, the webkit scroll bar styles; more specifically the thumb and the track style. When the scroller is at rest, the thumb (2pt) and the track (3pt) are using a transparent border which gives it a thinner appearance. Whereas in active mode, i.e. when the user hovers over it, custom-scroll directive intercepts the event and applies the class custom-scroll-vertical-hover. In this case, the thumb and the track are not using any border, which in turn gives the scroll bar a growing effect. In reality, it’s width is always 10px!

There you have it! 🏆

Div with custom and interactive scroller

Note: Scroll bar customization is browser-specific. Not all browsers allow modifications to the default implementation. The above solution is only supported by webkit browsers — Chrome, Safari, and Edge.

The appearance of the scroll bar can be customized as per need by just changing the colors in the style.css file. Similarly, we can extend the solution to customize the horizontal scroll bar by targeting -webkit-scrollbar-thumb:horizontal and -webkit-scrollbar-track:horizontal respectively

I hope you found this article useful. Feel free to use this in your project.

You can download the source code for this article from github.

--

--