npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

potatoscroll

v0.6.3

Published

Custom scrollbar but still native scroll engine

Readme

PotatoScroll

Custom scrollbar but still native scroll engine.

Demo: https://dobrapyra.github.io/PotatoScroll/


Usage

JS

Standalone library

<script src="./dist/potato-scroll.min.js"></script>

ES6 module

Install
npm install --save potatoscroll
Import
import PotatoScroll from 'potatoscroll';

Initialize

Global create multiple instances
PotatoScroll.create({ selector: '.scroll' });
Individual create of each instance
new PotatoScroll({ el: document.querySelector('.scroll--main') });
new PotatoScroll({ el: document.querySelector('.scroll--nested') });

HTML

Example HTML

<div class="scroll scroll--main">
  <div class="innerBox">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
    <div class="scroll scroll--nested">
      <div class="innerBox">
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
      </div>
    </div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus voluptatem, dicta fuga saepe vitae vel autem repudiandae, suscipit quae id aliquid voluptate, reprehenderit explicabo dolorum adipisci eaque perferendis sapiente. Ipsum.</p>
  </div>
</div>

CSS

Example CSS

.potatoScroll__mask {
  z-index: 0; }

.potatoScroll__track {
  background-color: rgba(0, 0, 0, 0.1);
  transition: background-color 0.2s; }
  .potatoScroll__track--v {
    width: 4px;
    top: 0;
    bottom: 0;
    right: 0;
    transition: width 0.2s, background-color 0.2s; }
    .potatoScroll__track--v:hover {
      width: 12px; }
    .potatoScroll--arrows .potatoScroll__track--v {
      top: 12px;
      bottom: 12px; }
    [dir=rtl] .potatoScroll__track--v {
      right: auto;
      left: 0; }
  .potatoScroll__track--h {
    height: 4px;
    left: 0;
    right: 0;
    bottom: 0;
    transition: height 0.2s, background-color 0.2s; }
    .potatoScroll__track--h:hover {
      height: 12px; }
    .potatoScroll--arrows .potatoScroll__track--h {
      left: 12px;
      right: 12px; }

.potatoScroll__bar {
  z-index: 1;
  position: absolute;
  background-color: rgba(0, 0, 0, 0.2);
  cursor: pointer;
  transition: background-color 0.2s; }
  .potatoScroll__bar:hover {
    background-color: rgba(0, 0, 0, 0.8); }
  .potatoScroll__bar--v {
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    transition: width 0.2s, background-color 0.2s; }
  .potatoScroll__bar--h {
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    transition: height 0.2s, background-color 0.2s; }

.potatoScroll__arrow {
  z-index: 1;
  position: absolute;
  background-color: rgba(0, 0, 0, 0.2);
  cursor: pointer;
  transition: background-color 0.2s; }
  .potatoScroll__arrow:hover {
    background-color: rgba(0, 0, 0, 0.8); }
  .potatoScroll__arrow--disabled {
    cursor: default; }
    .potatoScroll__arrow--disabled:hover {
      background-color: rgba(0, 0, 0, 0.2); }
  .potatoScroll__arrow--t, .potatoScroll__arrow--b {
    left: 0;
    width: 100%;
    height: 12px; }
  .potatoScroll__arrow--t {
    top: -12px; }
  .potatoScroll__arrow--b {
    bottom: -12px; }
  .potatoScroll__arrow--l, .potatoScroll__arrow--r {
    top: 0;
    height: 100%;
    width: 12px; }
  .potatoScroll__arrow--l {
    left: -12px; }
  .potatoScroll__arrow--r {
    right: -12px; }

SCSS

Example SCSS

.potatoScroll{
  $rootEl: &;
  $arrowSize: 12px;

  &__mask {
    z-index: 0;
  }

  &__track{
    background-color: rgba(0,0,0,0.1);
    transition: background-color 0.2s;

    &--v{
      width: 4px;
      top: 0;
      bottom: 0;
      right: 0;
      transition: width 0.2s, background-color 0.2s;

      &:hover{
        width: 12px;
      }

      #{$rootEl}--arrows & {
        top: $arrowSize;
        bottom: $arrowSize;
      }

      [dir=rtl] & {
        right: auto;
        left: 0;
      }
    }

    &--h{
      height: 4px;
      left: 0;
      right: 0;
      bottom: 0;
      transition: height 0.2s, background-color 0.2s;

      &:hover{
        height: 12px;
      }

      #{$rootEl}--arrows & {
        left: $arrowSize;
        right: $arrowSize;
      }
    }
  }

  &__bar{
    z-index: 1;
    position: absolute;
    background-color: rgba(0,0,0,0.2);
    cursor: pointer;
    transition: background-color 0.2s;

    &:hover{
      background-color: rgba(0,0,0,0.8);
    }

    &--v{
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      transition: width 0.2s, background-color 0.2s;
    }

    &--h{
      width: 100%;
      height: 100%;
      left: 0;
      top: 0;
      transition: height 0.2s, background-color 0.2s;
    }
  }

  &__arrow {
    z-index: 1;
    position: absolute;
    background-color: rgba(0,0,0,0.2);
    cursor: pointer;
    transition: background-color 0.2s;

    &:hover{
      background-color: rgba(0,0,0,0.8);
    }

    &--disabled {
      cursor: default;

      &:hover{
        background-color: rgba(0,0,0,0.2);
      }
    }

    &--t,
    &--b {
      left: 0;
      width: 100%;
      height: $arrowSize;
    }

    &--t {
      top: -$arrowSize;
    }

    &--b {
      bottom: -$arrowSize;
    }

    &--l,
    &--r {
      top: 0;
      height: 100%;
      width: $arrowSize;
    }
    
    &--l {
      left: -$arrowSize;
    }
    
    &--r {
      right: -$arrowSize;
    }
  }
}

Default styles file

<link rel="stylesheet" type="text/css" media="screen" href="./dist/potato-scroll.css" />

Options

All available options with their default values:

// global create
PotatoScroll.create({
  selector: undefined, // required, String - CSS selector string
  // ... // all single instance options exclude el
});

// or / and

// single instance create
new PotatoScroll({
  el: undefined, // required, Element
  maskEl: null, // own maskEl, Element
  scrollEl: null, // own scrollEl, Element
  cssClass: 'potatoScroll', // custom css class name for scrollbar styling
  forceCustom: false, // forces to use custom scrollbar on touch devices and macOS
  forceSize: 20, // offset for forceCustom to hide native scrollbar
  withArrows: false, // add arrow buttons to the tracks
  arrowMove: 40, // offset triggered by single click of arrow button
  onNativeScroll: function(element) {}, // on scroll event
  onScroll: function(progress, element) {}, // throttled on scroll event (progress is in range 0 - 1)
  onTop: function(element) {}, // on top event
  onBottom: function(element) {}, // on bottom event
  onLeft: function(element) {}, // on left event
  onRight: function(element) {}, // on right event
});

| Option | Type | Default | Description | | --- | --- | --- | --- | | selector | String | undefined | Only for create() method | | el | Element | undefined | Only for single instance constructor (new PotatoScroll()) | | maskEl | Element | null | Only for single instance constructor1 | | scrollEl | Element | null | Only for single instance constructor1 | | cssClass | String | "potatoScroll" | Custom css class, all classes are generate in BEM | | forceCustom | Boolean | false | Forces to use custom scrollbar on touch devices and macOS | | forceSize | Number | 20 | Offset value used by forceCustom to hide native scrollbar | | withArrows | Boolean | false | Enables arrow buttons on the tracks | | arrowMove | Number | 40 | Offset value triggered by single click of arrow button |

  1. Pass both maskEl & scrollEl to use own DOM tree mode Correct DOM tree example:
<div class="potatoScroll"> <!-- el -->
  <div class="potatoScroll__mask"> <!-- maskEl -->
    <div class="potatoScroll__scroll"> <!-- scrollEl -->
       <!-- scroll content -->
    </div>
  </div>
</div>

Constructors

| Method | Return | Description | | --- | --- | --- | | new PotatoScroll(options) | single PotatoScroll instance | The el property is required in the options object. | | PotatoScroll.create(options) | array of PotatoScroll instances | Creates multiple instances by css selector.1The selector property is required in the options object. |

  1. A single instance for each element catched by css selector

Methods

| Method | Return | Description | | --- | --- | --- | | refresh() | undefined | Recalculates content size and set scrollbars size | | destroy() | undefined | Destroys the instance and restore original html | | initialize() | undefined | Reinitializes the instance after destroy |


Events

| Event | Arguments | Triggered by | | --- | --- | --- | | onNativeScroll(e, el) | e {Event} native scroll eventel {Element} the instance's root element | Native scroll event. | | onScroll(progressObj, el) | progressObj {Object} progress of the scroll in two axis as object {v, h}.1 Each value {Number} is in range 0 - 1el {Element} the instance's root element | Throttled scroll event.2 | | onTop(el) | el {Element} the instance's root element | Scroll to top edge | | onBottom(el) | el {Element} the instance's root element | Scroll to bottom edge | | onLeft(el) | el {Element} the instance's root element | Scroll to left edge | | onRight(el) | el {Element} the instance's root element | Scroll to right edge |

  1. The v is vertical axis value & this h is horizontal axis value.
  2. This event is throttled using requestAnimationFrame.

by dobrapyra