OverlayScrollbars is a javascript scrollbar plugin that hides native scrollbars, provides custom styleable overlay scrollbars and keeps the native functionality and feeling.
Why
I've created this plugin because I hate ugly and space consuming scrollbars. Similar plugins haven't met my requirements in terms of features, quality, simplicity, license or browser support.
Goals & Features
- Simple, powerful and good documented API
- High browser compatibility - Firefox, Chrome, Opera, Edge, Safari 10+ and IE 11
- Tested on various devices - Mobile, Desktop and Tablet
- Tested with various (and mixed) inputs - Mouse, touch and pen
- Treeshaking - bundle only what you really need
- Automatic update detection - no polling
- Usage of latest browser features - best performance in new browsers
- Bidirectional - LTR or RTL direction support
- Simple and effective scrollbar styling
- TypeScript support - fully written in TypeScript
Getting started
npm & Node
OverlayScrollbars can be downloaded from npm or the package manager of your choice:
npm install overlayscrollbars
After installation it can be imported:
import 'overlayscrollbars/overlayscrollbars.css';
import { OverlayScrollbars } from 'overlayscrollbars';
Manual download & embedding
You can use OverlayScrollbars without any bundler or package manager.
Simply download it from the Releases or use a CDN.
- Use the javascript files with the
.browser
extension. - If you target old browsers use the
.es5
javascript file, for new browsers .es6
. - For production use the javascript / stylesheet files with the
.min
extension.
Embedd OverlayScrollbars manually in your HTML:
<link type="text/css" href="path/to/overlayscrollbars.css" rel="stylesheet" />
<script type="text/javascript" src="path/to/overlayscrollbars.js" defer></script>
Initialization
Note During initialization its expected that the CSS file is loaded and parsed by the browser.
You can initialize either directly with an Element
or with an Object
where you have more control over the initialization process.
const osInstance = OverlayScrollbars(document.querySelector('#myElement'), {});
Initialization with an Object
Note For now please refer to the TypeScript definitions for a more detailed description of all possibilities.
The only required field is the target
field. This is the field to which the plugin is applied to.
If you use the object initialization only with the target
field, the outcome is equivalent to the element initialization:
OverlayScrollbars(document.querySelector('#myElement'), {});
OverlayScrollbars({ target: document.querySelector('#myElement') }, {});
In the initialization object you can specify how the library is handling generated elements.
For example you can appoint an existing element as the viewport
element. Like this the library won't generate it but take the specified element instead:
OverlayScrollbars({
target: document.querySelector('#target'),
elements: {
viewport: document.querySelector('#viewport'),
},
}, {});
This is very useful if you have a fixed DOM structure and don't want OverlayScrollbars to generate its own elements. Those cases arise very often when you want an other library to work together with OverlayScrollbars.
You can also decide to which element the scrollbars should be applied to:
OverlayScrollbars({
target: document.querySelector('#target'),
scrollbars: {
slot: document.querySelector('#target').parentElement,
},
}, {});
And last but not least you can decide when the initialization should be canceled:
OverlayScrollbars({
target: document.querySelector('#target'),
cancel: {
nativeScrollbarsOverlaid: true,
body: null,
}
}, {});
In the above example the initialization is canceled when the native scrollbars are overlaid or when your target is a body
element and the plugin determined that a initialization to the body
element would affect native functionality like window.scrollTo
.
Options
You can initialize OverlayScrollbars with an initial set of options, which can be changed at any time with the options
method:
OverlayScrollbars(document.querySelector('#myElement'), {
overflow: {
x: 'hidden',
},
});
Options in depth
The default options are:
const defaultOptions = {
paddingAbsolute: false,
showNativeOverlaidScrollbars: false,
update: {
elementEvents: [['img', 'load']],
debounce: [0, 33],
attributes: null,
ignoreMutation: null,
},
overflow: {
x: 'scroll',
y: 'scroll',
},
scrollbars: {
theme: 'os-theme-dark',
visibility: 'auto',
autoHide: 'never',
autoHideDelay: 1300,
dragScroll: true,
clickScroll: false,
pointers: ['mouse', 'touch', 'pen'],
},
};
paddingAbsolute
Indicates whether the padding for the content shall be absolute.
showNativeOverlaidScrollbars
Indicates whether the native overlaid scrollbars shall be visible.
update.elementEvents
type | default |
---|
Array<[string, string]> | null | [['img', 'load']] |
An array of tuples. The first value in the tuple is an selector
and the second value are event names
. The plugin will update itself if any of the elements with the specified selector will emit any specified event. The default value can be interpreted as "The plugin will update itself if any img
element emits an load
event."
update.debounce
type | default |
---|
[number, number] | number | null | [0, 33] |
Note If 0 is used for the timeout, requestAnimationFrame
instead of setTimeout
is used for the debounce.
Debounces the MutationObserver
which tracks changes to the content. If a tuple is passed, the first value is the timeout and second is the max wait. If only a number is passed you specify only the timeout and there is no max wait. With null there is no debounce. Usefull to fine-tune performance.
update.attributes
type | default |
---|
string[] | null | null |
Note There is a base array of attributes that the MutationObserver
always observes, even if this option is null
.
An array of additional attributes that the MutationObserver
should observe for the content.
update.ignoreMutation
type | default |
---|
((mutation) => any) | null | null |
A function which receives a MutationRecord
as an argument. If the function returns a truthy value the mutation will be ignored and the plugin won't update. Usefull to fine-tune performance.
overflow.x
type | default |
---|
string | 'scroll' |
Note Valid values are: 'hidden'
, 'scroll'
, 'visible'
, 'visible-hidden'
and 'visible-scroll'
.
The overflow behavior for the horizontal (x) axis.
overflow.y
type | default |
---|
string | 'scroll' |
Note Valid values are: 'hidden'
, 'scroll'
, 'visible'
, 'visible-hidden'
and 'visible-scroll'
.
The overflow behavior for the vertical (y) axis.
scrollbars.theme
type | default |
---|
string | null | 'os-theme-dark' |
Applies the specified theme (classname) to the scrollbars.
scrollbars.visibility
Note Valid values are: 'visible'
, 'hidden'
, and 'auto'
.
The base visibility of the scrollbars.
scrollbars.autoHide
Note Valid values are: 'never'
, 'scroll'
, 'leave'
and 'move'
.
The possibility to hide visible scrollbars automatically after a certain user action.
scrollbars.autoHideDelay
The delay in milliseconds before the scrollbars are hidden automatically.
scrollbars.dragScroll
Indicates whether you can drag the scrollbar handles for scrolling.
scrollbars.clickScroll
Indicates whether you can click on the scrollbar track for scrolling.
scrollbars.pointers
type | default |
---|
string[] | null | ['mouse', 'touch', 'pen'] |
The PointerTypes
the plugin should react to.
Events
You can initialize OverlayScrollbars with an initial set of events, which can be managed at any time with the on
and off
methods:
OverlayScrollbars(document.querySelector('#myElement'), {}, {
updated(osInstance, onUpdatedArgs) {
}
});
Events in depth
Note Every event receives the instance
from which it was fired as the first argument. Always.
initialized
arguments | description |
---|
instance | The instance which fired the event. |
Is fired after all generated elements, observers and events were appended to the DOM.
updated
arguments | description |
---|
instance | The instance which fired the event. |
onUpdatedArgs | An object which describes the update in detail. |
Note If an update was triggered but nothing changed, the event won't be fired.
Is fired after the instace was updated.
destroyed
arguments | description |
---|
instance | The instance which fired the event. |
canceled | An boolean which indicates whether the initialization was canceled and thus destroyed. |
Is fired after all generated elements, observers and events were removed from the DOM.
Instance Methods
Note For now please refer to the TypeScript definitions for a more detailed description.
interface OverlayScrollbars {
options(): Options;
options(newOptions: DeepPartial<Options>): Options;
update(force?: boolean): OverlayScrollbars;
destroy(): void;
state(): State;
elements(): Elements;
on<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>): () => void;
on<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>[]): () => void;
off<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>): void;
off<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>[]): void;
}
Static Methods
Note For now please refer to the TypeScript definitions for a more detailed description.
interface OverlayScrollbarsStatic {
(target: InitializationTarget): OverlayScrollbars | undefined;
(
target: InitializationTarget,
options: DeepPartial<Options>,
eventListeners?: InitialEventListeners
): OverlayScrollbars;
plugin(plugin: Plugin | Plugin[]): void;
valid(osInstance: any): boolean;
env(): Environment;
}
|
Thanks to BrowserStack for sponsoring open source projects and letting me test OverlayScrollbars for free.
|
Future Plans
- Provide plugin based support for missing features. (treeshakeable)
- Frequent updates in terms of bug-fixes and enhancements. (always use latest browser features)
- Improve tests. (unit & browser tests)
License
MIT