Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

overlayscrollbars

KingSora1.9mMIT2.11.1TypeScript support: included

A javascript scrollbar plugin that hides the native scrollbars, provides custom styleable overlay scrollbars, and preserves the native functionality and feel.

overlayscrollbars, custom, styleable, scrollbar, scrollbars, scroll, frontend, browser

readme


Downloads Version License Code Coverage Max. Bundle Size

Website   •   Examples

OverlayScrollbars

A javascript scrollbar plugin that hides the native scrollbars, provides custom styleable overlay scrollbars, and preserves the native functionality and feel.

Why?

I created this plugin because I hate ugly and space-consuming scrollbars. Similar plugins didn't meet my requirements in terms of features, quality, simplicity, license or browser support.

Goals & Features

  • Simple, powerful and well-documented API.
  • High browser compatibility - Firefox 59+, Chrome 55+, Opera 42+, Edge 15+ and Safari 10+.
  • Fully Accessible - Native scrolling behavior is fully preserved.
  • Can run on the server (Node, Deno and Bun) - SSR, SSG and ISR support.
  • 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 required.
  • Leverage latest browser features - best performance in new browsers.
  • Flow independent - supports all values for direction, flex-direction and writing-mode.
  • Supports scroll snapping.
  • Supports all virtual scrolling libraries.
  • Supports the body element.
  • Easy and effective scrollbar styling.
  • Highly customizable.
  • TypeScript support - completely written in TypeScript.
  • Dependency-free - 100% self-written to ensure small size and best functionality.
  • High quality and fully typed framework versions for react, vue, angular, svelte and solid.

Choose your framework

In addition to the vanilla JavaScript version, you can use the official framework components & utilities:

React Vue Angular Svelte Solid

Getting started

npm & nodejs

OverlayScrollbars can be downloaded from npm or the package manager of your choice:

npm install overlayscrollbars

Once installed, it can be imported:

import 'overlayscrollbars/overlayscrollbars.css';
import { 
  OverlayScrollbars, 
  ScrollbarsHidingPlugin, 
  SizeObserverPlugin, 
  ClickScrollPlugin 
} from 'overlayscrollbars';

Note: If the path 'overlayscrollbars/overlayscrollbars.css' is not working use 'overlayscrollbars/styles/overlayscrollbars.css' as the import path for the CSS file.

You can use this Node Example as an reference / starting point.

Manual Download & Embedding

You can use OverlayScrollbars without any bundler or package manager.
Simply download one of the Releases or use a CDN.

  • Use the javascript files with the .browser extension.
  • Use the javascript files with the .es5 extension if you need to support older browsers, otherwise use the .es6 files.
  • For production use the javascript / stylesheet files with the .min extension.

Embed OverlayScrollbars manually in your HTML:

<link type="text/css" href="path/to/overlayscrollbars.css" rel="stylesheet" />
<script type="text/javascript" src="path/to/overlayscrollbars.browser.es.js" defer></script>

Use the global variable OverlayScrollbarsGlobal to access the api similar to how you can do it in nodejs / modules:

var { 
  OverlayScrollbars, 
  ScrollbarsHidingPlugin, 
  SizeObserverPlugin, 
  ClickScrollPlugin  
} = OverlayScrollbarsGlobal;

You can use this Browser Example as an reference or a starting point.

The examples in this documentation use the import syntax instead of the OverlayScrollbarsGlobal object. However, both versions are equivalent.

Initialization

The initialization of OverlayScrollbars is explicit per element. Only the scrollbars of the element on which the plugin is initialized will be changed. Scrollbars of child elements will remain unchanged unless the plugin is initialized on them as well.

You can either initialize a new instance directly with an Element or with an Object where you have more control over the initialization process.

// Simple initialization with an element
const osInstance = OverlayScrollbars(document.querySelector('#myElement'), {});

Bridging initialization flickering

When you initialize OverlayScrollbars, it takes a few milliseconds to create and append all the elements to the DOM. During this time, the native scrollbars are still visible and will be switched out after the initialization is finished. This is seen as flickering.

To fix this behavior apply the data-overlayscrollbars-initialize attribute to the target element (and the html element as well when initializing a scrollbar for the body element).

<!-- for the body element -->
<html data-overlayscrollbars-initialize>
  <head></head>
  <body data-overlayscrollbars-initialize></body>
</html>

<!-- for all other elements -->
<div data-overlayscrollbars-initialize>
  OverlayScrollbars is applied to this div
</div>

Initialization with an Object

<summary> This is an in depth topic. Click here to read it. </summary>

The only required field is the target field. This is the field to which the plugin will be applied.
If you use the object initialization with only the target field, the result is equivalent to the element initialization:

// Both initializations have the same outcome

OverlayScrollbars(document.querySelector('#myElement'), {});
OverlayScrollbars({ target: document.querySelector('#myElement') }, {});

When initializing with an object you can specify how the library handles generated elements. For example, you can specify an existing element as the `viewport' element. Then the library won't generate it, but use 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 create its own elements. These cases are very common when you want another library to work 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,
  },
}, {});

Last but not least, you can decide when to cancel the initialization:

OverlayScrollbars({ 
  target: document.querySelector('#target'),
  cancel: {
    nativeScrollbarsOverlaid: true,
    body: null,
  }
}, {});

In the above example, the initialization will be aborted if the native scrollbars are overlaid, or if your target is a body element and the plugin has determined that initializing to the body element would interfere with native functionality such as 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

<summary> This is an in depth topic. Click here to read it. </summary>

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,
    autoHideSuspend: false,
    dragScroll: true,
    clickScroll: false,
    pointers: ['mouse', 'touch', 'pen'],
  },
};

paddingAbsolute

type default
boolean false

Indicates whether the padding for the content should be absolute.

showNativeOverlaidScrollbars

type default
boolean false

Indicates whether the native overlaid scrollbars should 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 emits any of the specified events. The default value can be interpreted as "The plugin will update itself if any img element emits a load event."

update.debounce

type default
[number, number] | number | null [0, 33]

Note: If 0 is used for the timeout, requestAnimationFrame will be used instead of setTimeout 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 it is treated as the timeout and there is no max wait. With null there is no debounce. Useful 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 the content for.

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. Useful 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

type default
string 'auto'

Note: Valid values are: 'visible', 'hidden', and 'auto'.

The visibility of a scrollbar if its scroll axis is able to have a scrollable overflow. (Scrollable overflow for an axis is only possible with the overflow behavior set to 'scroll' or 'visible-scroll').

scrollbars.autoHide

type default
string 'never'

Note: Valid values are: 'never', 'scroll', 'leave' and 'move'.

Dictates whether to hide visible scrollbars automatically after a certain user action.

scrollbars.autoHideDelay

type default
number 1300

The delay in milliseconds before the scrollbars are automatically hidden.

scrollbars.autoHideSuspend

type default
boolean false

Suspend the autoHide functionality until the first scroll interaction is performed.
The default value for this option is false for backwards compatibility reasons but is recommended to be true for better accessibility.

scrollbars.dragScroll

type default
boolean true

Indicates whether you can drag the scrollbar handles for scrolling.

scrollbars.clickScroll

type default
boolean | 'instant' false

Note: If set to true the ClickScrollPlugin is required.

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.

TypeScript

// The options of a OverlayScrollbars instance.
type Options = {
  // Whether the padding should be absolute.
  paddingAbsolute: boolean;
  // Whether to show the native scrollbars. Has effect only if the native scrollbars are overlaid.
  showNativeOverlaidScrollbars: boolean;
  // Customizes the automatic update behavior.
  update: {
    /**
     * The given Event(s) from the elements with the given selector(s) will trigger an update.
     * Useful for everything the MutationObserver and ResizeObserver can't detect
     * e.g.: An image's `load` event or the `transitionend` / `animationend` events.
     */
    elementEvents: Array<[elementSelector: string, eventNames: string]> | null;
    /**
     * The debounce which is used to detect content changes.
     * If a tuple is provided you can customize the `timeout` and the `maxWait` in milliseconds.
     * If a single number customizes only the `timeout`.
     *
     * If the `timeout` is `0`, a debounce still exists (and is done via `requestAnimationFrame` instead of `setTimeout`).
     */
    debounce: [timeout: number, maxWait: number] | number | null;
    /**
     * HTML attributes which will trigger an update if they're changed.
     * Basic attributes like `id`, `class`, `style` etc. are always observed and don't have to be added explicitly.
     */
    attributes: string[] | null;
    // A function which makes it possible to ignore a content mutation or null if nothing should be ignored.
    ignoreMutation: ((mutation: MutationRecord) => any) | null;
  };
  // Customizes the overflow behavior per axis.
  overflow: {
    // The overflow behavior of the horizontal (x) axis.
    x: OverflowBehavior;
    // The overflow behavior of the vertical (y) axis.
    y: OverflowBehavior;
  };
  // Customizes appearance of the scrollbars.
  scrollbars: {
    // The scrollbar's theme. The theme value will be added as `class` to all `scrollbar` elements of the instance.
    theme: string | null;
    // The scrollbar's visibility behavior.
    visibility: ScrollbarsVisibilityBehavior;
    // The scrollbar's auto hide behavior.
    autoHide: ScrollbarsAutoHideBehavior;
    // The scrollbar's auto hide delay in milliseconds.
    autoHideDelay: number;
    // Whether the scrollbar's auto hide behavior is suspended until a scroll happened.
    autoHideSuspend: boolean;
    // Whether it is possible to drag the handle of a scrollbar to scroll the viewport.
    dragScroll: boolean;
    // Whether it is possible to click the track of a scrollbar to scroll the viewport.
    clickScroll: ScrollbarsClickScrollBehavior;
    // An array of pointer types that shall be supported.
    pointers: string[] | null;
  };
};

// The overflow behavior of an axis.
type OverflowBehavior =
  // No scrolling is possible and the content is clipped.
  | 'hidden'
  // No scrolling is possible and the content isn't clipped.
  | 'visible'
  // Scrolling is possible if there is an overflow.
  | 'scroll'
  /**
   * If the other axis has no overflow the behavior is similar to `visible`.
   * If the other axis has overflow the behavior is similar to `hidden`.
   */
  | 'visible-hidden'
  /**
   * If the other axis has no overflow the behavior is similar to `visible`.
   * If the other axis has overflow the behavior is similar to `scroll`.
   */
  | 'visible-scroll';

// The scrollbars visibility behavior.
type ScrollbarsVisibilityBehavior =
  // The scrollbars are always visible.
  | 'visible'
  // The scrollbars are always hidden.
  | 'hidden'
  // The scrollbars are only visibile if there is overflow.
  | 'auto';

// The scrollbars auto hide behavior
type ScrollbarsAutoHideBehavior =
  // The scrollbars are never hidden automatically.
  | 'never'
  // The scrollbars are hidden unless the user scrolls.
  | 'scroll'
  // The scrollbars are hidden unless the pointer moves in the host element or the user scrolls.
  | 'move'
  // The scrollbars are hidden if the pointer leaves the host element or unless the user scrolls.
  | 'leave';

// The scrollbar click scroll behavior.
type ScrollbarsClickScrollBehavior = boolean | 'instant';

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

<summary> This is an in depth topic. Click here to read it. </summary>

Note: Every event receives the instance from which it was dispatched as the first argument. Always.

initialized

arguments description
instance The instance which dispatched the event.

Dispatched after all generated elements, observers and events were appended to the DOM.

updated

arguments description
instance The instance which dispatched 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 dispatched.

Dispatched after the instance was updated.

destroyed

arguments description
instance The instance which dispatched the event.
canceled A boolean which indicates whether the initialization was canceled and thus destroyed.

Dispatched after all generated elements, observers and events were removed from the DOM.

scroll

arguments description
instance The instance which dispatched the event.
event The original event argument of the DOM event.

Dispatched by scrolling the viewport.

TypeScript

// A mapping between event names and their listener arguments.
type EventListenerArgs = {
  // Dispatched after all elements are initialized and appended.
  initialized: [instance: OverlayScrollbars];
  // Dispatched after an update.
  updated: [instance: OverlayScrollbars, onUpdatedArgs: OnUpdatedEventListenerArgs];
  // Dispatched after all elements, observers and events are destroyed.
  destroyed: [instance: OverlayScrollbars, canceled: boolean];
  // Dispatched on scroll.
  scroll: [instance: OverlayScrollbars, event: Event];
};

interface OnUpdatedEventListenerArgs {
  // Hints which describe what changed in the DOM.
  updateHints: {
    // Whether the size of the host element changed.
    sizeChanged: boolean;
    // Whether the direction of the host element changed.
    directionChanged: boolean;
    // Whether the intrinsic height behavior changed.
    heightIntrinsicChanged: boolean;
    // Whether the overflow edge (clientWidth / clientHeight) of the viewport element changed.
    overflowEdgeChanged: boolean;
    // Whether the overflow amount changed.
    overflowAmountChanged: boolean;
    // Whether the overflow style changed.
    overflowStyleChanged: boolean;
    // Whether the scroll coordinates changed.
    scrollCoordinatesChanged: boolean;
    // Whether an host mutation took place.
    hostMutation: boolean;
    // Whether an content mutation took place.
    contentMutation: boolean;
  };
  // The changed options.
  changedOptions: PartialOptions;
  // Whether the update happened with force-invalidated cache.
  force: boolean;
}

Instance

The OverlayScrollbars instance can be created by calling the OverlayScrollbars function with an element and options object.

const osInstance = OverlayScrollbars(document.body, {});

Instance Methods

<summary> This is an in depth topic. Click here to read it. </summary>

options(): Options

Get the current options of the instance.

returns description
Options The current options.

options(newOptions, pure?): Options

Sets the current options of the instance.

parameter type description
newOptions PartialOptions The new (partial) options which should be applied.
pure boolean | undefined Whether the options should be reset before the new options are added.
returns description
Options The complete new options.

on(eventListeners, pure?): Function

Adds event listeners to the instance.

parameter type description
eventListeners EventListeners An object which contains the added listeners. The fields are the event names and the listeners.
pure boolean | undefined Whether all already added event listeners should be removed before the new listeners are added.
returns description
Function A function which removes all added event listeners.

on(name, listener): Function

Adds a single event listener to the instance.

parameter type description
name string The event name.
listener Function The function invoked when the event is dispatched.
returns description
Function A function which removes the added event listener.

on(name, listeners): Function

Adds multiple event listeners to the instance.

parameter type description
name string The event name.
listeners Function[] The functions invoked when the event is dispatched.
returns description
Function A function which removes the added event listeners.

off(name, listener): void

Removes a single event listener from the instance.

parameter type description
name string The event name.
listener Function The function to be removed.

off(name, listeners): void

Removes multiple event listeners from the instance.

parameter type description
name string The event name.
listeners Function[] The functions to be removed.

update(force?): boolean

Updates the instance.

parameter type description
force boolean | undefined Whether the update should force the cache to be invalidated.
returns description
Function A boolean which indicates whether the update event was triggered through this update.

state(): State

Gets the instance's state.

returns description
State An object describing the state of the instance.

elements(): Elements

Gets the instances elements.

returns description
Elements An object describing the elements of the instance.

destroy(): void

Destroys the instance and removes all added elements.

plugin(plugin: object): object | undefined

Gets the instance modules instance of the passed plugin.

returns description
object | undefined An object which describes the plugins instance modules instance or undefined if no instance was found.

TypeScript

  // A simplified version of the OverlayScrollbars TypeScript interface.
  interface OverlayScrollbars {
    // Get the current options of the instance.
    options(): Options;
    // Sets the current options of the instance.
    options(newOptions: PartialOptions, pure?: boolean): Options;

    // Adds event listeners to the instance.
    on(eventListeners: EventListeners, pure?: boolean): () => void;
    // Adds a single event listener to the instance.
    on<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>): () => void;
    // Adds multiple event listeners to the instance.
    on<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>[]): () => void;

    // Removes a single event listener from the instance.
    off<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>): void;
    // Removes multiple event listeners from the instance.
    off<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>[]): void;

    // Updates the instance.
    update(force?: boolean): boolean;

    // Gets the instance's state.
    state(): State;

    // Gets the instance's elements.
    elements(): Elements;

    // Destroys the instance and removes all added elements.
    destroy(): void;

    // Gets the instance modules instance of the passed plugin.
    plugin<P extends InstancePlugin>(osPlugin: P): InferInstancePluginModuleInstance<P> | undefined;
  }

  // Describes a OverlayScrollbars instances state.
  interface State {
    // Describes the current padding in pixels.
    padding: TRBL;
    // Whether the current padding is absolute.
    paddingAbsolute: boolean;
    // The client width (x) & height (y) of the viewport in pixels.
    overflowEdge: XY<number>;
    // The overflow amount in pixels.
    overflowAmount: XY<number>;
    // The css overflow style of the viewport.
    overflowStyle: XY<OverflowStyle>;
    // Whether the viewport has an overflow.
    hasOverflow: XY<boolean>;
    // The scroll coordinates of the viewport.
    scrollCoordinates: {
      // The start (origin) scroll coordinates for each axis.
      start: XY<number>;
      // The end scroll coordinates for each axis.
      end: XY<number>;
    };
    // Whether the direction is considered rtl.
    directionRTL: boolean;
    // Whether the instance is considered destroyed.
    destroyed: boolean;
  }

  // Describes the elements of a OverlayScrollbars instance.
  interface Elements {
    // The element the instance was applied to.
    target: HTMLElement;
    // The host element. It's the root of all other elements.
    host: HTMLElement;
    /**
     * The element responsible for the correct padding.
     * Depending on initialization it can be the same as the viewport element.
     */
    padding: HTMLElement;
    // The element responsible of the scrolling.
    viewport: HTMLElement;
    /**
     * The element responsible for holding the actual content.
     * Depending on initialization it can be the same as the viewport element.
     */
    content: HTMLElement;
    /**
     * The element through which you can get the current `scrollLeft` or `scrollTop` offset.
     * Depending on the target element it can be the same as the viewport element.
     */
    scrollOffsetElement: HTMLElement;
    /**
     * The element through which you can add `scroll` events.
     * Depending on the target element it can be the same as the viewport element.
     */
    scrollEventElement: HTMLElement | Document;
    // The horizontal scrollbar's elements.
    scrollbarHorizontal: CloneableScrollbarElements;
    // The vertical scrollbar's elements.
    scrollbarVertical: CloneableScrollbarElements;
  }

Static Object

The static OverlayScrollbars object.

OverlayScrollbars.plugin(SomePlugin);

Static Object Methods

<summary> This is an in depth topic. Click here to read it. </summary>

valid(osInstance): boolean

Checks whether the passed value is a valid and not destroyed overlayscrollbars instance

parameter type description
osInstance any The value to be checked.
returns description
boolean Whether the passed value is a valid and not destroyed overlayscrollbars instance.

env(): Environment

Gets the environment.

returns description
Environment An object describing the environment.

nonce(newNonce): void

Sets the nonce attribute for inline styles.

parameter type description
newNonce string | undefined The new nonce attribute for inline styles.

trustedTypePolicy(newTrustedTypePolicy): void

Sets the trusted type policy.

parameter type description
newTrustedTypePolicy TrustedTypePolicy | undefined The new trusted type policy.

plugin(plugin): object | undefined

Adds a single plugin.

parameter type description
plugin object The plugin to be added.
returns description
object | void An object describing the plugin's static module instance or void if no instance was found.

plugin(plugins): (object | void)[]

Adds multiple plugins.

parameter type description
plugins object[] The plugins to be added.
returns description
(object | void)[] An array describing the plugins static modules instances or undefined if no instance was found.

TypeScript

  // The OverlayScrollbars static object.
  interface OverlayScrollbarsStatic {
    // Gets the instance of the passed target or `undefined` the target has no instance.
    (target: InitializationTarget): OverlayScrollbars | undefined;
    // Initializes OverlayScrollbars to the passed target with passed options and event listeners.
    (target: InitializationTarget, options: PartialOptions, eventListeners?: EventListeners): OverlayScrollbars;

    // Checks whether the passed value is a valid and not destroyed overlayscrollbars instance.
    valid(osInstance: any): osInstance is OverlayScrollbars;

    // Gets the environment.
    env(): Environment;

    // Sets the nonce attribute for inline styles.
    nonce(newNonce: string | undefined): void;

    // Adds a single plugin.
    plugin(plugin: Plugin): InferStaticPluginModuleInstance<Plugin>
    // Adds multiple plugins.
    plugin(plugins: Plugin[]): InferStaticPluginModuleInstance<Plugin>[];
  }

  // Describes the OverlayScrollbars environment.
  interface Environment {
    // The native scrollbars size of the browser / system.
    scrollbarsSize: XY<number>;
    // Whether the native scrollbars are overlaid.
    scrollbarsOverlaid: XY<boolean>;
    // Whether the browser supports native scrollbar hiding.
    scrollbarsHiding: boolean;
    // Whether the browser supports the ScrollTimeline API.
    scrollTimeline: boolean;
    // The default Initialization to use if nothing else is specified.
    staticDefaultInitialization: Initialization;
    // The default Options to use if nothing else is specified.
    staticDefaultOptions: Options;

    // Returns the current default Initialization.
    getDefaultInitialization(): Initialization;
    // Returns the current default Options.
    getDefaultOptions(): Options;

    /**
     * Sets a new default Initialization.
     * If the new default Initialization is partially filled, its deeply merged with the current default Initialization.
     * @param newDefaultInitialization The new default Initialization.
     * @returns The current default Initialization.
     */
    setDefaultInitialization(newDefaultInitialization: PartialInitialization): Initialization;
    /**
     * Sets new default Options.
     * If the new default Options are partially filled, they're deeply merged with the current default Options.
     * @param newDefaultOptions The new default Options.
     * @returns The current default options.
     */
    setDefaultOptions(newDefaultOptions: PartialOptions): Options;
  }

Styling

OverlayScrollbars comes with two themes called os-theme-dark and os-theme-light. You can use the scrollbars.theme option to change the theme.

Custom themes can be done in several ways. The easiest and fastest way is to use the predefined set of CSS Custom Properties aka CSS variables. If that's not enough, you can add custom class names or add custom styling to the existing class names.

Styling in depth

<summary> This is an in depth topic. Click here to read it. </summary>

CSS Custom properties

OverlayScrollbars provides a set of CSS Custom Properties which makes scrollbar styling easy and fast:

  .os-scrollbar {
    // The size of the scrollbar
    --os-size: 0;
    // The axis-perpendicular padding of the scrollbar (horizontal: padding-y, vertical: padding-x)
    --os-padding-perpendicular: 0;
    // The axis padding of the scrollbar (horizontal: padding-x, vertical: padding-y)
    --os-padding-axis: 0;
    // The border radius of the scrollbar track
    --os-track-border-radius: 0;
    // The background of the scrollbar track
    --os-track-bg: none;
    // The :hover background of the scrollbar track
    --os-track-bg-hover: none;
    // The :active background of the scrollbar track
    --os-track-bg-active: none;
    // The border of the scrollbar track
    --os-track-border: none;
    // The :hover background of the scrollbar track
    --os-track-border-hover: none;
    // The :active background of the scrollbar track
    --os-track-border-active: none;
    // The border radius of the scrollbar handle
    --os-handle-border-radius: 0;
    // The background of the scrollbar handle
    --os-handle-bg: none;
    // The :hover background of the scrollbar handle
    --os-handle-bg-hover: none;
    // The :active background of the scrollbar handle
    --os-handle-bg-active: none;
    // The border of the scrollbar handle
    --os-handle-border: none;
    // The :hover border of the scrollbar handle
    --os-handle-border-hover: none;
    // The :active border of the scrollbar handle
    --os-handle-border-active: none;
    // The min size of the scrollbar handle
    --os-handle-min-size: 33px;
    // The max size of the scrollbar handle
    --os-handle-max-size: none;
    // The axis-perpendicular size of the scrollbar handle (horizontal: height, vertical: width)
    --os-handle-perpendicular-size: 100%;
    // The :hover axis-perpendicular size of the scrollbar handle (horizontal: height, vertical: width)
    --os-handle-perpendicular-size-hover: 100%;
    // The :active axis-perpendicular size of the scrollbar handle (horizontal: height, vertical: width)
    --os-handle-perpendicular-size-active: 100%;
    // Increases the interactive area of the scrollbar handle.
    --os-handle-interactive-area-offset: 0;
  }

You can change the properties for both scrollbars at once, or for each scrollbar axis. In the example below, I've chosen os-theme-custom as the theme name:

  // Horizontal and vertical scrollbar are 10px 
  .os-theme-custom {
    --os-size: 10px;
  }

  // Horizontal scrollbar is 10px
  .os-theme-custom.os-scrollbar-horizontal {
    --os-size: 10px;
  }
  // Vertical scrollbar is 20px
  .os-theme-custom.os-scrollbar-vertical {
    --os-size: 20px;
  }

You can then use your theme by assigning it via the scrollbars.theme option:

  OverlayScrollbars(document.body, {
    scrollbars: {
      theme: 'os-theme-custom'
    }
  });

Since scrollbar styles are usually simple, this set of options should be enough to get the styling you want. If you need more freedom, you can create your own styles by adding styling to the base class names described in the next section.

Scrollbars structure and CSS class names

The scrollbars HTML markup looks like:

  <div class="os-scrollbar os-scrollbar-horizontal">
      <div class="os-scrollbar-track">
          <div class="os-scrollbar-handle">
          </div>
      </div>
  </div>
  <div class="os-scrollbar os-scrollbar-vertical">
      <div class="os-scrollbar-track">
          <div class="os-scrollbar-handle">
          </div>
      </div>
  </div>

The class names are simplified, in a real application the .os-scrollbar element can have additional class names which modify the appearance (mostly visibility and alignment).

Below is a list of the most important class names you will encounter:

CSS class name description
.os-scrollbar The root element of a scrollbar.
.os-scrollbar-rtl Indicates a RTL direction of the host element the scrollbar belongs to.
.os-scrollbar-horizontal The root element of a horizontal scrollbar.
.os-scrollbar-vertical The root element of a vertical scrollbar.
.os-scrollbar-handle-interactive Indicates that the handle inside the scrollbar is interactive (scrollbars.dragScroll is not false).
.os-scrollbar-track-interactive Indicates that the track inside the scrollbar is interactive (scrollbars.clickScroll is not false).
.os-scrollbar-track The track element. This is the track of the nested handle element. If scrollbars.clickScroll is not false this is the element users can click to change the scroll offset.
.os-scrollbar-handle The handle element. If scrollbars.dragScroll is not false this is the handle users can drag to change the scroll offset.

If you create your own theme, please only use the classes listed above. All other classes are modifier classes used to change visibility, alignment and pointer-events of the scrollbars.

Gotchas

It is important that the chosen theme class name in your CSS file matches the assigned theme name in the options. If the CSS class name is .my-theme, the scrollbars.theme must be 'my-theme'.

Please be aware of your stack. For example, css-modules will change your class names to avoid naming collisions. Always check that your CSS is what you expect it to be.

Plugins

Anything that is not considered core functionality or old browser compatibility is exposed via a plugin. This is done because all unused plugins are omitted during treeshaking and won't end up in your final bundle. OverlayScrollbars ships with the following plugins:

Consuming Plugins

Plugins are consumed like:

import { 
  OverlayScrollbars, 
  ScrollbarsHidingPlugin, 
  SizeObserverPlugin, 
  ClickScrollPlugin 
} from 'overlayscrollbars';

// Single plugin
OverlayScrollbars.plugin(ScrollbarsHidingPlugin);

// Multiple plugins
OverlayScrollbars.plugin([SizeObserverPlugin, ClickScrollPlugin]);

Plugins in depth

<summary> This is an in depth topic. Click here to read it. </summary>

Plugins are plain objects with a single field, the name of the field is the name of the plugin. This name is the plugin's identifier and must be unique across all plugins. In case multiple plugins have the same name, the last added plugin overwrites the plugin added previously under the same name.

Plugin Modules

A Plugin module is the constructor of a plugin module's instance. There are two kinds of plugin modules: static and instance. A single plugin must have one or more modules. A plugin module can return an instance, but doesn't have to.

Static Plugin Module

The static plugin module is invoked when the plugin is added with the OverlayScrollbars.plugin function.

Example plugin with a static module:

const staticPlugin = {
  // Plugin has the name `examplePlugin`.
  examplePlugin: {
    // The `static` function describes a static module and returns the module instance or void / undefined if no instance is needed.
    // The `osStatic` parameter is the global `OverlayScrollbars` object.
    static: (osStatic) => {
      let count = 0;
      const staticPluginModuleInstance = {
        getCount: () => count,
        increment: () => { count++ },
      }
      return staticPluginModuleInstance;
    }
  }
}

When the plugin is added with the OverlayScrollbars.plugin function, the static module instance is returned:

const staticModuleInstance = OverlayScrollbars.plugin(staticPlugin); // Plugins static module is invoked
staticModuleInstance.count; // 0
staticModuleInstance.increment();
staticModuleInstance.count; // 1

Instance Plugin Module

The instance plugin module is invoked when a new OverlayScrollbars instance is created but before the initialized event is dispatched.

Example plugin with a instance module:

const instancePlugin = {
  // Plugin has the name `examplePlugin`.
  examplePlugin: {
    // Instance function describes na instance module and returns the module instance or void / undefined if no instance is needed.
    // The `osInstance` parameter is the OverlayScrollbar instance the plugin is bound to.
    // The `event` parameter is a function which adds events to the instance which can't be removed from outside the plugin.
    // The `osStatic` parameter is the global OverlayScrollbar object.
    instance: (osInstance, event, osStatic) => {
      let count = 0;

      const instancePluginModuleInstance = {
        getCount: () => count,
        increment: () => { count++ },
      }

      // Event which fires when the instance was initialized.
      event('initialized', () => {
        console.log("instance initialized");
      });

      // Event which fires when the viewport was scrolled.
      const removeScrollEvent = event('scroll', () => {
        console.log("viewport scrolled");
        removeScrollEvent(); // Removes the event after the first scroll.
      });

      return instancePluginModuleInstance;
    }
  }
}

When the plugin is added with the OverlayScrollbars.plugin function, all OverlayScrollbar instances will automatically add the plugin from that point on. Previously created instances will not have the plugin. The instance module instance is returned with the osInstance.plugin function:

OverlayScrollbars.plugin(instancePlugin); // Plugin is added

const osInstance = OverlayScrollbars(document.body, {}); // Plugin's instance module is invoked
const instancePluginInstance = osInstance.plugin(instancePlugin);

instancePluginInstance.count; // 0
instancePluginInstance.increment();
instancePluginInstance.count; // 1

TypeScript

// Describes a OverlayScrollbar plugin.
type Plugin<
  // The name of the plugin.
  Name extends string = string,
  // The module instance type of the static module.
  S extends PluginModuleInstance | void = PluginModuleInstance | void, 
  // The module instance type of the instance module.
  I extends PluginModuleInstance | void = PluginModuleInstance | void 
> = {
  [pluginName in Name]: PluginModule<S, I>;
};

// Describes a OverlayScrollbar plugin which has only a static module.
type StaticPlugin<
  Name extends string = string,
  T extends PluginModuleInstance = PluginModuleInstance
> = Plugin<Name, T, void>;

// Describes a OverlayScrollbar plugin which has only a instance module.
type InstancePlugin<
  Name extends string = string,
  T extends PluginModuleInstance = PluginModuleInstance
> = Plugin<Name, void, T>;

// Infers the type of the static module's instance of the passed plugin.
type InferStaticPluginModuleInstance<T extends StaticPlugin>;

// Infers the type of the instance modules instance of the passed plugin.
type InferInstancePluginModuleInstance<T extends InstancePlugin>;

FAQ

<summary> How do I get / set the scroll position of an element I applied OverlayScrollbars to? </summary>

If you applied OverlayScrollbars to the body element you can use window.scrollX, window.scrollY, window.scroll, window.scrollTo, window.scrollBy or any other native api.

If the plugin was applied to any other element you have to get the viewport element with the instance.elements() function first. With this element you can use element.scrollTop, element.scrollLeft, element.scroll, element.scrollTo, element.scrollBy or any other native api.

const { viewport } = osInstance.elements();
const { scrollLeft, scrollTop } = viewport; // Get scroll offset
viewport.scrollTo({ top: 0 }); // Set scroll offset
<summary> Is it possible to limit / adjust the scrollbar handle length? </summary>

You can adjust a scrollbar's handle length by setting a min-width / min-height and max-width / max-height style:

/* horizontal boundaries */
.os-scrollbar-horizontal .os-scrollbar-handle {
  min-width: 50px;
  max-width: 200px;
}
/* vertical boundaries */
.os-scrollbar-vertical .os-scrollbar-handle {
  min-height: 40px;
  max-height: 40px;
}

You can assign the same value to both properties to force the scrollbar to be always the same size.
Setting the width and height properties won't work since those are set by the plugin automatically.

Feature comparison to v1

  • The scroll function is missing. Planned as a plugin. (WIP)
  • Initialization to the textarea element isn't supported yet. Planned as a plugin. (WIP)

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)

Used by

Sponsors

Thanks to BrowserStack for sponsoring open source projects and letting me test OverlayScrollbars for free.

License

MIT

changelog

Changelog

2.11.1

Improvements

  • Use the ResizeObservers options.box option to remove the need for additional DOM elements in supported browsers.
  • Significant performance improvements in the update logic.

2.11.0

Features

Improvements

  • Change ScrollAnimationTimeline keyframes to not animate css-custom-properties to improve scroll performance. #705

2.10.1

Improvements

  • Add pen to the list of "hoverable" pointer devices. #690

2.10.0

Features

  • The option scrollbars.clickScroll now supports the value 'instant'. The ClickScrollPlugin is not required for it to work. #645

Improvements

  • Rewrite clickScroll animation for better performance and to support in and out easing for a smoother animation.

2.9.2

Improvements

  • Improve initialization and update performance by determining if a non-default scroll direction is possible before measuring scroll coordinates. #655

2.9.1

Improvements

  • Resilience against scroll-behavior: smooth style when scrolling should be instant.

2.9.0

Features

  • Add the possibility to define a nonce value for websites with a CSP. #646

Improvements

  • Reduced bundle size due to removed compatiblity code.
  • clickScroll will not cancel on fast clicks / taps. #650
  • Add easing to the clickScroll animation.
  • The scrollbar-handle offset and size calculations are now entirely in CSS and will not force reflows.
  • Use custom css properties for setting the scrollbar-handle offset and size.

Bug Fixes

  • Only take the initial scroll coordinates from the viewport element if it has a scrollable overflow. (Otherwise take the initial scroll coordinates from the target element) #652

2.8.4

Improvements

  • The scrollbar handle size is now updated if the corresponding scrollbar element has an transition.

2.8.3

Improvements

  • Improvements to update performance.
  • Added automated e2e performance metrics.

2.8.2

Bug Fixes

  • Fix a bug where children attribute mutations were not picked up if the new attribute value was an empty string.

2.8.1

Improvements

  • Improve the scrollCoordinates logic introduced in v2.8.0 to have better defaults in cases of ambiguity.
  • The scroll event is not propagated if it is an result of scrollCoordinates detection during update.
  • Focus management improvements.

2.8.0

Breaking Changes

  • Although not a major release, I've decided to remove the rtlScrollBehavior field from the Environment object. The reason for it is a switch of how the library now detects scroll coordinates for non default flow directions. The replacement for this field is the scrollCoordinates field of the State object for each instance.

Features

  • Support non default flow directions (block and inline) not only direction: rtl. #625
  • A new field scrollCoordinates in the State object. It indicates the min. and max. scroll coordinates for the viewport. (useful for non default flow direction scrolling)
  • A new field scrollCoordinatesChanged in the updateHints object. It indicates whether the scroll coordinates changed in an update.

Improvements

  • Fix a Firefox only behavior where releasing a scrollbar handle over an anchor would trigger the anchor and navigate to it.
  • Change zoom detection: instead of the window.resize event, the window.matchMedia event is used.
  • Greatly improve how dragging and releasing the scrollbar handle behaves for scroll-snapped viewports.

Bug Fixes

  • Fix a bug here pointer capture was released too early for wacom pen devices. #630

2.7.3

Improvements

  • Use { preventScroll: true } when focusing viewport to prevent unwanted scrolling. #629
  • Make the scrollbars hidden when @media print applies. #628

2.7.2

Bug Fixes

  • Handle case where document.defaultView is null. #627

2.7.1

Improvements

  • When interacting with a scrollbar the viewport element gets focused under certain conditions. (Like e.g. the previously focused element is not and interactive element.)
  • Move the environment styles from the stylesheet into javascript to remove the requirement of loaded styles for correct functionality.

2.7.0

Improvements

  • Improvements for running in deno and bun.
  • Initialization as the body element is now detected as such when the tag name of the target element is "body". Previously this detection was done with target === target.ownerDocument.body which would not work when creating a new body element in memory.
  • If a non generated elements.viewport element is provided during initialization its scroll position will be taken as the initial scroll position instead of the scroll position of the target element.
  • When interacting with the scrollbars itself the scrollbars.autoHideDelay will now apply when the scrollbars would be auto hidden when the interaction ends.

2.6.1

Bug Fixes

  • Fully remove lingering IE11 compatibility code which overwrote previously set height styles.

2.6.0

Improvements

  • Add focusin and focusout to the focus and blur event management when wrapping and unwrapping elements. #605
  • The scrollbars.visibility option was unintuitive to use for adjusting visibility per axis. Its now only applied if the scrollbars scroll axis is able to have a scrollable overflow. #611

2.5.0

Breaking Changes

  • Although not a major release, I've decided to drop IE11 support in this version. This change should be beneficial to the majority of users.
    • The size of the js bundle decreased by ~6%.
    • The size of the css bundle decreased by ~18%.
    • The fields flexboxGlue and cssCustomProperties are removed from the Environment. (returning object from OverlayScrollbars.env())

Improvements

  • Streamlining of scroll related calculations, including RTL direction.
  • Focus and Blur event management when wrapping and unwrapping elements during initialization and destroy. #605

2.4.7

Improvements

  • Adapt the exports field in the package.json for correct commonjs and module handling.
  • Additional types exports: Elements, State, CloneableScrollbarElements, ScrollbarElements, StaticInitialization and DynamicInitialization.
  • Remove obsolete styles when initializing OverlayScrollbars on the body element and the browser supports native scrollbar hiding. #601
  • Move code to the ScrollbarsHidingPlugin for better treeshaking.

2.4.6

Bug Fixes

  • If the pointer (mouse, pen etc.) is interacting with the scrollbar, the autoHide option will wait until the interaction is finished. #597
  • ScrollTimeline animations are not canceled anymore when they are updated. Instead the animations keyframe effect is switched out preventing flickering. #598

2.4.5

Improvements

  • Its now possible to have a height / width transition on the scrollbar-handle. #587

2.4.4

Bug Fixes

  • Fix a bug where ScrollTimeline animation keyframe could contain NaN or Infinity values triggering a warning. #581
  • Treat explicitly assigned undefined values for options as if they would be left out. #586

2.4.3

Bug Fixes

  • Bug where the instance wasn't updated when the window resized. #578

Improvements

  • Further improvements to the update strategy to make finer grained updates.

2.4.2

Improvements

  • Makes custom instance plugins compatible with "pure" environments such as react and all other component frameworks / libraries.

2.4.1

Improvements

  • Add compatibility exports field to package.json so the 'overlayscrollbars/styles/overlayscrollbars.css' import works in all node versions. #570

2.4.0

Features

  • Finalize and document the plugin system which makes it possible to create "static" and / or "instance" plugins.
  • The static OverlayScrollbars.plugin function returns a "static" plugins instance(s) for the registered plugins.
  • A new instance.plugin function which returns a "instance" plugins instance.
  • window resize events will now update instances only if it is needed and only what is needed.

Improvements

  • Small internal rewrite to improve stability, performance and bundle size.
  • Improvements the documentation and README.

2.3.2

Bug Fixes

2.3.1

Bug Fixes

  • Fix direction rtl visual scrollbar handle behavior in browser which support the ScrollTimeline API.
  • Fix double tap behavior for interactive elements on iOS devices if autoHide is leave or move. #560 #285
  • Fix incorrect scrollbar handle calculation when overscroll on safari occurred. #559

2.3.0

Features

  • Make use of the new ScrollTimeline API in supported browsers.
  • Add the option scrollbars.autoHideSuspend to make it possible to suspend the autoHide functionality until the first scroll interaction was performed. The default value for this option is false for backwards compatibility reasons but is recommended to be true for better accessibility.
  • Add a CSS selector to bridge deferred initializations visually.

Bug Fixes

  • Fix a bug where a change wasn't detected properly when the target element was hidden initially. #546
  • Fixed a bug where the scroll offset was reset to 0 sometimes after initialization when the target was the body element.

Improvements

  • Add online examples to README.

2.2.1

Bug Fixes

  • Fix an issue where the viewport element could be wider than the host element. #538

Improvements

  • Instead of offsetWidth & offsetHeight use the corresponding properties from the getBoundingClientRect object to increase accuracy of scrollbar calculations. #542

2.2.0

Improvements

  • Force the scroll-behavior css property to be auto when the user interacts with a scrollbar to prevent smooth scrolling to apply where it shouldn't. #515
  • The viewort, padding and content elements don't use the class attribute anymore for their styling. Instead each of them uses its own data-overlayscrollbars-* attribute. This has been done so that 3rd party libraries aren't conflicting with classnames from overlayscrollbars or vice versa. Selectors like .os-viewport, .os-padding or .os-content won't work anymore. #526 #530

2.1.1

Bug Fixes

  • Fixed a bug where pointer events weren't released properly after drag or click scrolling. #512

Improvements

  • The os-theme-dark and os-theme-light themes now use border-box box-sizing as their default.
  • Improve the README.md documentation for initialization, styling and and the browser global version. #509

2.1.0

Bug Fixes

  • Fix a bug where initial RTL direction wasn't detected properly.

Features

  • Introduce CSS Custom Properties to improve theming and styling of scrollbars. #478

Improvements

  • Improve pointer event handling on scrollbar handle and track.
  • Improve the README documentation with a styling section.

2.0.3

Bug Fixes

  • Revert the viewport and padding style position: relative change introduced in v2.0.2 due to breaking behavior. #489 is considered a design limitation.

2.0.2

Bug Fixes

  • The viewport and padding elements won't have the style position: relative anymore if its not needed. The style is only needed for older browsers. (#489)

2.0.1

Bug Fixes

  • The custom scrollbars are now always hidden if the showNativeOverlaidScrollbars option is true.

Improvements

  • The initialization to the body element respects now overflow: hidden style overrides of the html and body element. (#477)
  • data-overlayscrollbars-initialize is now automatically removed if the instance is destroyed or canceled.
  • data-overlayscrollbars-initialize now always sets overflow: auto to prevent elements to be suddenly cropped after initialization.
  • removed obsolete !important styles

2.0.0

OverlayScrollbars was rewritten from the ground up in TypeScript in a functional manner. The rewrite comes with multiple benefits:

  • The library is much smaller now (about 50% smaller fully treeshaken)
  • Modern browsers benefit greatly because compat code is inside plugins which are treeshaken if unused
  • Multiple performance optimizations were made due to the new structure
  • Framework Components benefit of the pure parameter for options and events (same input produces same output)
  • TypeScript definitions are always up to date (@types/overlayscrollbars is obsolete now)

New Features:

  • If applied to body all the native functionality in modern browsers (e.g. swipe down to refresh on mobile, scroll restoration etc.) is preserved (#376, #425, #273, #320)
  • If you scroll while the cursor hovers a scrollbar element the viewport is now scrolled (#128, #322)
  • The initialization process can be fully customized now. This makes it possible to itegrate with other plugins / libraries (#432, #304, #149, #148, #139, #49)
  • Scrollbars can be cloned and positioned anywhere in the DOM tree. (#404, #323, #158, #17)
  • The update behavior of the MutationObserver for the content can be customized with the update options. (#307, #183, #23)
  • Works now without adjustments with CSS-Grid, CSS-Flexbox etc.
  • Supports all kind of input devices additionally to mouse and touch. (Uses native pointer-events now)
  • Exports a esm version which can be treeshaken

Breaking changes:

  • Browser support changed. The minimal version is now IE11.
  • There is no default export anymore. The main entry point is now the OverlayScrollbars named export.
  • The styles are now exported under a different path. Read the docs for more info.
  • The scroll function is missing. (WIP will be added as a plugin)
  • Initialization to textarea element is not suppored. (WIP will be added as a plugin)
  • extensions are replaced with plugins. Plugins are more powerful but work nothing like extensions.
  • Any helper functions for extensions are removed.
  • TypesScript definitions changed completely.
  • CSS styles changed completely.
  • There is no jQuery version anymore and no jQuery compat functionality
  • The following changed for the initialization:
    • Arrays of elements are not supported anymore. If you want to initialize the plugin to multiple elements, you have to loop over them.
    • Since the initialization is now fully customizable, the plugin won't have special behavior anymore if it has children with os- classnames
    • The third parameter are events now instead of eventsions since extensions are removed
  • The following options were removed / replaced / renamed:

    • resize is removed
    • sizeAutoCapable is removed (works always now)
    • clipAlways is removed (works automatically now)
    • normalizeRTL is removed since the scroll function isn't implemented yet there is nothing to normalize
    • autoUpdate is removed since all browser support the MutationObserver api there is no need for customizing a update loop
    • autoUpdateInterval is removed
    • className is replaced with scrollbars.theme
    • updateOnLoad is replaced with update.elementEvents
    • nativeScrollbarsOverlaid.initialize is replaced with the Initialization concept. You can pass a object as target now where you can specify when to cancel the initialization of the plugin.
    • nativeScrollbarsOverlaid.showNativeScrollbars: is renamed to showNativeOverlaidScrollbars
    • scrollbars.dragScrolling is renamed to scrollbars.dragScroll
    • scrollbars.clickScrolling is renamed to scrollbars.clickScroll and animates the scroll change only with the ClickScrollPlugin otherwise its instant
    • scrollbars.touchSupport is replaced with scrollbars.pointers
    • scrollbars.snapHandle is removed
    • textarea is removed since textarea initialization isn't possible yet
    • callbacks is removed / replaced with the events concept. You can pass listeners / callback separately to the options. The this context is now undefined as a replacement each event recieves the instance as its first argument.
      • onScrollStart is removed
      • onScrollStop is removed
      • onInitialized is replaced with the initialized event
      • onUpdated is replaced with the updated the
      • onDestroyed is replaced with the destroyed event
      • onScroll is replaced with the scroll event
      • onInitializationWithdrawn is replaced with the destroyed event (if the second argument canceled is true)
      • onOverflowChanged is replaced with the updated event (its second argument holds the information whether the overflow changed)
      • onOverflowAmountChanged is replaced with theupdated event (its second argument holds the information whether the overflow amount changed and how much)
      • onDirectionChanged is replaced with the updated event (its second argument holds the information whether the direction changed)
      • onContentSizeChanged is replaced with the updated event (its second argument holds the information whether the content got mutated)
      • onHostSizeChanged is replaced with the updated event (its second argument holds the information whether the host got mutated / its size changed)
  • The following instance methods were removed / replaced / renamed:

    • sleep() is removed since it doesn't fit into the new structure and shouldn't be needed anymore
    • ext() is removed
    • addExt() is removed
    • removeExt() is removed
    • scroll() is removed (WIP)
    • scrollStop() is removed (WIP)
    • getElements() is renamed to elements() and doesn't support any argumens anymore.
    • getState() is renamed to state() and doesn't support any argumens anymore.
  • The following static methods were removed / replaced / renamed:
    • extension() is removed
    • defaultOptions() is replaced with env().getDefaultOptions() and env().setDefaultOptions()
    • globals() is replaced with env()
  • If you used any fields from the globals() result, please refer to the TypeScript definitions for the correct replacement in env()

Theming changes:

  • Because scrollbars can be cloned and positioned anywhere in the DOM, themes which worked in v1 have to be adapted slightly:
    • .os-scrollbar elements now don't rely on its parent element. Selectors like .os-theme-dark > .os-scrollbar-vertical are now .os-theme-dark.os-scrollbar-vertical
    • the .os-host-rtl class is replaced with .os-scrollbar-rtl. Selectors like .os-theme-dark.os-host-rtl > .os-scrollbar-horizontal are now .os-theme-dark.os-scrollbar-rtl.os-scrollbar-horizontal