OverlayScrollbars: custom scrollbars that keep native scrolling intact
A javascript scrollbar plugin that hides the native scrollbars, provides custom styleable overlay scrollbars, and preserves the native functionality and feel.
At a glance
- What is it?
- OverlayScrollbars hides the native scrollbars of an element and replaces them with styleable overlays, without reimplementing scroll physics. It is a per-element plugin for teams that care about how scrollbars look and still want wheel, touch, keyboard and accessibility behaviour to work.
- Who is it for?
- Adopt OverlayScrollbars if you need scrollbars that match a design system while keeping native scroll physics, keyboard access and touch behaviour, and if you are willing to initialize it per element and style the overlay yourself. Do not adopt it if a CSS-only scrollbar treatment (scrollbar-width, scrollbar-color or a WebKit pseudo-element) already meets the design, or if you need a virtual scrolling list, which this is not.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 148 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The scrollbar problem OverlayScrollbars takes on
Native scrollbars are drawn by the browser, not by your stylesheet. Their width, color and shape differ per operating system and per browser, and until recently the only portable way to change them was a set of vendor pseudo-elements that never covered every engine. OverlayScrollbars takes the other route: it hides the native scrollbar of a specific element and draws its own scrollbar in a layer on top of the content, while the element keeps scrolling the way the browser scrolls it.
The author is direct about the motivation. The README says the plugin exists because "I hate ugly and space-consuming scrollbars", and that similar plugins did not meet the requirements in features, quality, simplicity, license or browser support. That framing explains the design: the project is not a scrolling engine, it is a scrollbar skin with a strict rule that native functionality and feel stay in place.
The audience follows from that. It is for frontend teams building an application shell, a panel, a modal body or a sidebar where the scrollbar is visible and part of the visual language, and where replacing the scroll behaviour would break something else. It is a poor fit for a page whose whole scroll experience you intend to control yourself.
How the plugin works: per-element initialization, plugins and an overlay layer
Initialization is explicit and per element. The README states that "the initialization of OverlayScrollbars is explicit per element" and that "only the scrollbars of the element on which the plugin is initialized will be changed". There is no global stylesheet that restyles every scroll container on the page, and no automatic scanning of the DOM. If you want the treatment on ten elements, you initialize ten elements.
The package ships an API object plus several opt-in plugins, named in the README as ScrollbarsHidingPlugin, SizeObserverPlugin and ClickScrollPlugin. That split is what makes treeshaking meaningful: a build that does not import ClickScrollPlugin does not carry it. The plugin also documents automatic update detection with no polling required, which suggests the library reacts to size changes rather than running a timer loop.
Several claims in the feature list are about what the library does not take over. It states that native scrolling behavior is fully preserved and that the result is fully accessible. It states support for all values of direction, flex-direction and writing-mode, which matters because an overlay scrollbar has to know which edge it belongs on. It also states that it can run on the server under Node, Deno and Bun, so server-side rendering does not break when the module is imported.
Installing OverlayScrollbars from npm and initializing one element
The README gives npm as the primary distribution channel. The install command is a plain npm install with no flags:
npm install overlayscrollbarsAfter that, the README shows a single import of the stylesheet followed by a named import of the API and the optional plugins. Both paths are documented because the shorter one does not resolve in every setup:
import 'overlayscrollbars/overlayscrollbars.css';
import {
OverlayScrollbars,
ScrollbarsHidingPlugin,
SizeObserverPlugin,
ClickScrollPlugin
} from 'overlayscrollbars';The README adds a note: if 'overlayscrollbars/overlayscrollbars.css' does not work, use 'overlayscrollbars/styles/overlayscrollbars.css' instead. That is the first thing to check if the scrollbars render but look unstyled.
If you would rather not use a bundler, the README points to the releases page and to a CDN, and describes a manual embed. The link tag loads the stylesheet and the script tag loads the browser build with defer:
<link type="text/css" href="path/to/overlayscrollbars.css" rel="stylesheet" />
<script type="text/javascript" src="path/to/overlayscrollbars.browser.es.js" defer></script>In that mode the API is exposed on a global. The README shows destructuring from OverlayScrollbarsGlobal, which it says is equivalent to the module import:
var {
OverlayScrollbars,
ScrollbarsHidingPlugin,
SizeObserverPlugin,
ClickScrollPlugin
} = OverlayScrollbarsGlobal;The README also describes which build files to pick: the .browser files for the browser build, .es5 when older browsers must be supported and .es6 otherwise, and .min files for production. The repository carries runnable starting points under examples/ for browser, node, react, vue, angular, svelte and solid, and the README links a Node example and a Browser example as references.
Framework packages, and why the vanilla package is still the one doing the work
The repository is a workspace: package.json declares "workspaces": ["packages/*"], and the packages/ directory holds the core library plus overlayscrollbars-react, overlayscrollbars-vue, overlayscrollbars-ngx, overlayscrollbars-svelte and overlayscrollbars-solid. The README calls these "high quality and fully typed framework versions" and links each one.
The practical difference between the two routes is lifecycle. With the vanilla package you call the API yourself when an element mounts and dispose it when the element goes away. With a framework package that wiring is provided, so a component re-render does not leave a stale instance attached to a detached node. The framework packages do not change the rendering model underneath; they wrap the same core.
The licence situation is uniform, which is unusual for a project with this many packages. The repository LICENSE is MIT and the package metadata lists MIT, so the core library and the framework wrappers are distributed under the same terms. MIT is permissive and carries no copyleft obligation on your application. That is a statement about the licence text, not legal advice; if your organisation has a policy on third-party licences, run it through that policy rather than treating this paragraph as clearance.
Where OverlayScrollbars is the wrong tool
The most common mismatch is expecting a virtual scroller. OverlayScrollbars changes how the scrollbar looks; it does not reduce the number of DOM nodes you render. The README states that the plugin supports all virtual scrolling libraries, which is the opposite claim from being one. If your list has 50,000 rows, this library will not save you; it will render the scrollbar on top of whatever a virtualizer produces.
A second limit is scope. Because initialization is per element, an application with scroll containers created dynamically by a component library needs a hook at each of those creation points. The README does not document a global "apply to everything" mode, and it does not document a rollback or uninstall procedure beyond the API's own lifecycle. If you cannot reach the code that creates a scroll container, you cannot style its scrollbar with this library.
A third is the ceiling on what overlay scrollbars can be. On touch devices, where the operating system already draws transient scrollbars, an always-visible custom overlay can look out of place, and the README's device testing claims do not translate into a recommendation about when to show the overlay. The feature list also claims "leverage latest browser features" for best performance in new browsers, which is a trade-off stated plainly: the compatibility floor is Firefox 59+, Chrome 55+, Opera 42+, Edge 15+ and Safari 10+, and behaviour on very old engines is not the target.
OverlayScrollbars compared with CSS scrollbar styling
The real alternative for most teams is not another JavaScript plugin, it is CSS. Modern browsers expose scrollbar-width and scrollbar-color, and WebKit-derived engines expose ::-webkit-scrollbar and its sub-parts. That approach costs no JavaScript, adds no bundle weight, needs no initialization and cannot leak an instance. For a site that only wants a thinner, differently colored scrollbar, it is the better answer, and the honest advice is to try it first.
The difference in approach is what you get in exchange for the dependency. CSS styling cannot draw an overlay that floats above the content, cannot be themed with the same tokens as the rest of your components in a fully portable way, and gives you no API to query or control the scrollbar. OverlayScrollbars gives you a styleable element you own, plus an API and plugins, at the cost of a JavaScript dependency, a stylesheet import and per-element initialization. The README's own framing supports this reading: it lists easy and effective scrollbar styling and high customizability as goals, not automatic behaviour.
If you do want a JavaScript option and you have already decided against this one, the comparison to make is about scroll physics rather than styling. Libraries that implement their own smooth or virtual scrolling replace the browser's behaviour; OverlayScrollbars explicitly preserves it. Pick based on which of those two you actually need.
Editorial conclusion
Adopt OverlayScrollbars if you need scrollbars that match a design system while keeping native scroll physics, keyboard access and touch behaviour, and if you are willing to initialize it per element and style the overlay yourself. Do not adopt it if a CSS-only scrollbar treatment (scrollbar-width, scrollbar-color or a WebKit pseudo-element) already meets the design, or if you need a virtual scrolling list, which this is not. Before committing, verify two things in your own build: that the CSS import path resolves in your bundler (the README documents both 'overlayscrollbars/overlayscrollbars.css' and 'overlayscrollbars/styles/overlayscrollbars.css'), and that the elements you want covered are inside the set you initialize, because nothing is styled globally.
Frequently asked questions
What is an overlay scrollbar in OverlayScrollbars?
It is a scrollbar the plugin draws itself, positioned over the element's content, after the native scrollbar has been hidden. The README describes the plugin as hiding the native scrollbars, providing custom styleable overlay scrollbars, and preserving the native functionality and feel.
How do I use OverlayScrollbars in a project?
Install it from npm, import the stylesheet and the API, and initialize it on the element whose scrollbar you want to replace. Initialization is explicit per element, so only elements you initialize are affected.
What is OverlayScrollbars?
It is a JavaScript scrollbar plugin, written in TypeScript and distributed under the MIT licence, that hides native scrollbars, draws custom styleable overlay scrollbars, and preserves native scrolling functionality and feel. Official framework packages exist for React, Vue, Angular, Svelte and Solid.
What is a real alternative to OverlayScrollbars?
Styling the scrollbar with CSS, using scrollbar-width and scrollbar-color or the WebKit scrollbar pseudo-elements, is the closest alternative for appearance-only changes. It needs no JavaScript and no initialization, but it cannot draw a floating overlay or expose an API the way this plugin does.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kingsora-overlayscrollbars)