Nearly Past Midnight

    overlayscrollbars
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.3 • Public • Published

    Downloads Version License Code Coverage Max. Bundle Size

    OverlayScrollbars

    OverlayScrollbars is a javascript scrollbar plugin that hides native scrollbars, provides custom styleable overlay scrollbars and keeps the native functionality and feeling.

    Why

    I 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 well documented API
    • High browser compatibility - Firefox, Chrome, Opera, Edge, Safari 10+ and IE 11
    • Can be run on the server - 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
    • Usage of latest browser features - best performance in new browsers
    • Bidirectional - LTR or RTL direction support
    • Simple and effective scrollbar styling
    • Highly customizable
    • TypeScript support - fully 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

    Additionally to the vanilla JavaScript version you can use the official framework components & utilities:

    React Vue Angular Svelte Solid

    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';

    Note: In older node versions use 'overlayscrollbars/styles/overlayscrollbars.css' as the import path for the CSS file.

    Manual download & embedding

    These instructions are for quick prototyping or old stacks. Click here to read them.

    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.browser.js" defer></script>

    You can use the global variable OverlayScrollbarsGlobal to access the api:

    var OverlayScrollbars = OverlayScrollbarsGlobal.OverlayScrollbars;
    OverlayScrollbars(document.body, {});

    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.

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

    Bridging initialization flickering

    If you initialize OverlayScrollbars it needs a few milliseconds to create and append all the elements to the DOM. While this period the native scrollbars are still visible and are switched out after the initialization is finished. This is perceived as flickering.

    To fix this behavior apply the data-overlayscrollbars-initialize attribute to the target element (and html element if the target element is body).

    Initialization with an Object

    This is a in depth topic. Click here to read it.

    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:

    // Both initializations have the same outcome
    
    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

    This is a in depth topic. Click here to read it.

    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

    type default
    boolean false

    Indicates whether the padding for the content shall be absolute.

    showNativeOverlaidScrollbars

    type default
    boolean false

    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

    type default
    string 'auto'

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

    The base visibility of the scrollbars.

    scrollbars.autoHide

    type default
    string 'never'

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

    The possibility to hide visible scrollbars automatically after a certain user action.

    scrollbars.autoHideDelay

    type default
    number 1300

    The delay in milliseconds before the scrollbars are hidden automatically.

    scrollbars.dragScroll

    type default
    boolean true

    Indicates whether you can drag the scrollbar handles for scrolling.

    scrollbars.clickScroll

    type default
    boolean false

    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

    This is a in depth topic. Click here to read it.

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

    initialized

    arguments description
    instance The instance which invoked the event.

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

    updated

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

    Is invoked after the instace was updated.

    destroyed

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

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

    scroll

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

    Is invoked by scrolling the viewport.

    Instance

    Note: For now please refer to the TypeScript definitions for a more detailed description.

    interface OverlayScrollbars {
      options(): Options;
      options(newOptions: PartialOptions, pure?: boolean): Options;
    
      on(eventListeners: EventListeners, pure?: boolean): () => void;
      on<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>): () => void;
      on<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>[]): () => void;
    
      off<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>): void;
      off<N extends keyof EventListenerArgs>(name: N, listener: EventListener<N>[]): void;
    
      update(force?: boolean): boolean;
    
      state(): State;
    
      elements(): Elements;
    
      destroy(): 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: PartialOptions, eventListeners?: EventListeners): OverlayScrollbars;
    
      plugin(plugin: Plugin | Plugin[]): void;
    
      valid(osInstance: any): osInstance is OverlayScrollbars;
    
      env(): Environment;
    }

    Plugins

    Everything thats considered not core functionality or old browser compatibility is exposed via a plugin. This is done because all unused plugins are treeshaken and thus won't end up in your final bundle. OverlayScrollbars comes 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]);

    Writing Plugins

    Note: For now please refer to the TypeScript definitions for a more detailed description.

    You can write and publish your own Plugins. This section is a work in progress.

    FAQ

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

    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
    Is it possible to limit / adjust the scrollbar handle length?

    You can adjust a scrollbars 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)

    Sponsors

    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

    Install

    npm i overlayscrollbars

    DownloadsWeekly Downloads

    1,293,088

    Version

    2.0.3

    License

    MIT

    Unpacked Size

    4.23 MB

    Total Files

    20

    Last publish

    Collaborators

    • kingsora