LISN.js

Edit on StackBlitz

"use client";
import { useEffect, useRef } from "react";

import { LoadTrigger, Show, AutoHide } from "lisn.js";
import { ScrollbarComponent } from "@lisn.js/react";
import "lisn.js/scrollbar.css";

import styles from "./demo.module.css";

export default function Page() {
  const msgRef = useRef(null);

  useEffect(() => {
    const msg = msgRef.current;
    let widget: AutoHide;
    if (msg) {
      new LoadTrigger(msg, [new Show(msg)], {
        delay: 1000,
      });
      widget = new AutoHide(msg, { delay: 2500 });
    }

    return () => {
      // cleanup
      widget?.destroy();
    };
  }, []);

  return (
    <>
      <div className={styles.wrapper}>
        <p ref={msgRef} className={[styles.msg, "lisn-hide"].join(" ")}>
          Scroll the box
        </p>

        <ScrollbarComponent
          className={styles.demo}
          config={{ onMobile: true, autoHide: 2000, positionV: "top" }}
        >
          <div className={styles.section}>
            <h1>L</h1>
            <h4>Lightweight.</h4>

            <ul>
              <li>Vanilla TypeScript</li>
              <li>Highly optimized</li>
              <li>No layout thrashing</li>
            </ul>
          </div>

          <div className={styles.section}>
            <h1>I</h1>
            <h4>Interactive.</h4>

            <ul>
              <li>Powerful API</li>
              <li>Multi gesture support</li>
              <li>Mobile/touch ready</li>
            </ul>
          </div>

          <div className={styles.section}>
            <h1>S</h1>
            <h4>Simple.</h4>

            <ul>
              <li>Intuitive syntax</li>
              <li>Consistent API</li>
              <li>HTML-only mode</li>
            </ul>
          </div>

          <div className={styles.section}>
            <h1>N</h1>
            <h4>No-nonsense.</h4>

            <ul>
              <li>What says on the box</li>
              <li>Sensible defaults</li>
              <li>Highly customizable</li>
            </ul>
          </div>
        </ScrollbarComponent>
      </div>
    </>
  );
}
/* Container */
.wrapper {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  width: 100dvw;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.demo {
  --lisn-scrollbar--fg: var(--text-color);
  height: 400px;
  width: 800px;
  max-width: 100%;
  background: var(--bg-color-lighter);
  box-shadow: var(--lisn-shadow);
  color: var(--text-color);
  overflow: auto;
}

/* Content */
.section {
  height: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.demo h1 {
  margin: 0 auto;
  font-size: 75px;
  background-image: linear-gradient(
    45deg,
    var(--text-color) 42%,
    var(--text-color-lighter) 50%,
    var(--text-color) 58%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.demo h4 {
  font-size: clamp(20px, calc(15px + 2vw), 32px);
}

.demo ul {
  padding: 0;
  list-style-type: none;
}

.demo ul li {
  margin: 8px 0;
}

.demo ul li::before {
  content: "\2726";
  display: inline-block;
  font-size: 0.4em;
  transform: translateY(-0.4em);
  margin: 0 0.6em 0 0;
}

Edit on CodePen

document.addEventListener("DOMContentLoaded", () => {
  const scrollable = document.getElementById("demo");
  new LISN.widgets.Scrollbar(scrollable, {
    onMobile: true,
    autoHide: 2000,
    positionV: "top",
  });

  const msg = document.getElementById("msg");
  new LISN.triggers.LoadTrigger(msg, [new LISN.actions.Show(msg)], {
    delay: 1000,
  });
  new LISN.widgets.AutoHide(msg, { delay: 1500 });
});
<p id="msg" class="lisn-hide">Scroll the box</p>

<div id="demo" class="lisn-hide-scroll">
  <div class="section">
    <h1>L</h1>
    <h4>Lightweight.</h4>

    <ul>
      <li>Vanilla TypeScript</li>
      <li>Highly optimized</li>
      <li>No layout thrashing</li>
    </ul>
  </div>

  <div class="section">
    <h1>I</h1>
    <h4>Interactive.</h4>

    <ul>
      <li>Powerful API</li>
      <li>Multi gesture support</li>
      <li>Mobile/touch ready</li>
    </ul>
  </div>

  <div class="section">
    <h1>S</h1>
    <h4>Simple.</h4>

    <ul>
      <li>Intuitive syntax</li>
      <li>Consistent API</li>
      <li>HTML-only mode</li>
    </ul>
  </div>

  <div class="section">
    <h1>N</h1>
    <h4>No-nonsense.</h4>

    <ul>
      <li>What says on the box</li>
      <li>Sensible defaults</li>
      <li>Highly customizable</li>
    </ul>
  </div>
</div>
/* Container */
#demo {
  --lisn-scrollbar--fg: var(--text-color);
  height: 400px;
  width: 800px;
  max-width: 100%;
  background: #28283f;
  box-shadow: var(--lisn-shadow);
  color: var(--text-color);
  overflow: auto;
}

/* Content */
#demo .section {
  height: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

#demo h1 {
  margin: 0 auto;
  font-size: 75px;
  background-image: linear-gradient(
    45deg,
    var(--text-color) 42%,
    var(--text-color-lighter) 50%,
    var(--text-color) 58%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

#demo h4 {
  font-size: clamp(20px, calc(15px + 2vw), 32px);
}

#demo ul {
  padding: 0;
  list-style-type: none;
}

#demo ul li {
  margin: 8px 0;
}

#demo ul li::before {
  content: "\2726";
  display: inline-block;
  font-size: 0.4em;
  transform: translateY(-0.4em);
  margin: 0 0.6em 0 0;
}

Edit on CodePen

<p
  class="lisn-hide"
  data-lisn-on-load="@show +delay=1000"
  data-lisn-auto-hide="1500"
>
  Scroll the box
</p>

<div
  id="demo"
  class="lisn-hide-scroll"
  data-lisn-scrollbar="on-mobile=true | auto-hide=2000 | position-v=top"
>
  <div class="section">
    <h1>L</h1>
    <h4>Lightweight.</h4>

    <ul>
      <li>Vanilla TypeScript</li>
      <li>Highly optimized</li>
      <li>No layout thrashing</li>
    </ul>
  </div>

  <div class="section">
    <h1>I</h1>
    <h4>Interactive.</h4>

    <ul>
      <li>Powerful API</li>
      <li>Multi gesture support</li>
      <li>Mobile/touch ready</li>
    </ul>
  </div>

  <div class="section">
    <h1>S</h1>
    <h4>Simple.</h4>

    <ul>
      <li>Intuitive syntax</li>
      <li>Consistent API</li>
      <li>HTML-only mode</li>
    </ul>
  </div>

  <div class="section">
    <h1>N</h1>
    <h4>No-nonsense.</h4>

    <ul>
      <li>What says on the box</li>
      <li>Sensible defaults</li>
      <li>Highly customizable</li>
    </ul>
  </div>
</div>
/* Container */
#demo {
  --lisn-scrollbar--fg: var(--text-color);
  height: 400px;
  width: 800px;
  max-width: 100%;
  background: #28283f;
  box-shadow: var(--lisn-shadow);
  color: var(--text-color);
  overflow: auto;
}

/* Content */
#demo .section {
  height: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

#demo h1 {
  margin: 0 auto;
  font-size: 75px;
  background-image: linear-gradient(
    45deg,
    var(--text-color) 42%,
    var(--text-color-lighter) 50%,
    var(--text-color) 58%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

#demo h4 {
  font-size: clamp(20px, calc(15px + 2vw), 32px);
}

#demo ul {
  padding: 0;
  list-style-type: none;
}

#demo ul li {
  margin: 8px 0;
}

#demo ul li::before {
  content: "\2726";
  display: inline-block;
  font-size: 0.4em;
  transform: translateY(-0.4em);
  margin: 0 0.6em 0 0;
}

Scroll the box

L

Lightweight.

  • Vanilla TypeScript
  • Highly optimized
  • No layout thrashing

I

Interactive.

  • Powerful API
  • Multi gesture support
  • Mobile/touch ready

S

Simple.

  • Intuitive syntax
  • Consistent API
  • HTML-only mode

N

No-nonsense.

  • What says on the box
  • Sensible defaults
  • Highly customizable