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

react-procedural-scroller

v1.0.2

Published

A headless React hook for building infinite scroller components that display procedurally generated data, perfect for use cases like date scrollers, where row data is generated dynamically rather than fetched from a dataset. Notable features include: full

Readme

A headless React hook for building infinite scroller components that display procedurally generated data. Perfect for use cases like date scrollers, where row data is generated dynamically rather than fetched from a dataset.

  • ⚡️Full row/column virtualization for buttery-smooth performance.
  • ⤴️ Supports vertical and horizontal layouts.
  • 📏 Supports dynamic row/column sizes.
  • 🎯 A scrollToIndex API for instant or smooth programmatic scrolling.
  • 📦 Lightweight ~ 4.95 kB when minified and gzipped.
  • 🛠 Zero dependencies.
  • 🎭 E2E tested and rigorously vetted for rock-solid reliability.

Quick Start Guide

Follow the steps below to build your first procedural scroller component:

1. Install

Install the library using npm:

npm install react-procedural-scroller

2. Import

ES Modules:

import { useProceduralScroller } from "react-procedural-scroller";

CommonJS:

const { useProceduralScroller } = require("react-procedural-scroller");

3. Build UI Components

This library is headless, meaning it only manages the scrolling state and virtualization logic, giving you full freedom to design your own UI. To get started, you’ll first need to create two components: a scrollable <Container /> element, and an <Item /> component that will be rendered inside the container to form the rows/columns. Each item is identified by an integer index, and you can procedurally generate the item's content based on this index, as shown in the date scroller examples below:

Example container:

import { useProceduralScroller } from "react-procedural-scroller";
import Item from "../components/items/item.tsx";

export default function Container() {

  const { items, container } = useProceduralScroller<
    HTMLDivElement, // Type of the scrollable container element.
    HTMLDivElement // Type of each item inside the container.
  >({
    // Initial scroll position of the container.
    initialScroll: {
      index: 0, // Index of the item to scroll to initially.
      block: "center", // Alignment of the item in the viewport: "start", "center", or "end".
    },
    /* Callback to return the minimum size of each item along the relevant axis:
      - For vertical scrolling: minimum height.
      - For horizontal scrolling: minimum width. */
    getMinItemSize: () => 100,
    // Direction of scrolling: "vertical" or "horizontal"
    scrollDirection: "vertical",
    /* Optional: `initialContainerSize` defines the height of the container on the
    first page render. Without it, `items` will be null on the first render because the hook
    needs to measure the container's size before determining how many items to render.
    Providing a value makes `items` available immediately and helps avoid layout shift. */
    initialContainerSize: 200,
  });

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column", // Must match the hook's `scrollDirection`: "column" - vertical, "row" - horizontal.
        height: "500px",
        width: "500px",
        overflow: "scroll", // The container must be scrollable!
        border: "2px solid lightgrey",
        borderRadius: "10px",
        margin: "30px",
        scrollbarWidth: 'none',
      }}
      ref={container.ref} // Enables the hook to track and update the container's scroll position.
    >
      {items?.map((item) => (
        <Item key={item.index} item={item} />
      ))}
    </div>
  );
}

Example item:

import { memo } from 'react';
import { type Item } from 'react-procedural-scroller';

export default memo(
  function Item({ item }: { item: Item<HTMLDivElement> }) {

    /* Generate a date relative to today based on the item's index
       (e.g., index 0 = today, 1 = tomorrow, -1 = yesterday). */
    const date = new Date();
    date.setDate(date.getDate() + item.index);

    return (
      <div
        ref={item.ref} // Enables the hook to measure and virtualize this item.
        style={{
          minHeight: 100, // Must match or exceed the result of getMinItemSize(index) in the container.
          borderTop: '1px solid lightgrey',
        }}
      >
        <p
          style={{
            fontFamily: 'Helvetica',
            color: 'grey',
            padding: '10px',
          }}
        >
          {date.toDateString()}
        </p>
      </div>
    );
  },
  /*
   * Since an <Item /> component’s content is generated entirely from its index,
   * it is highly recommended to wrap it in React.memo with a custom comparison
   * function that prevents re-renders unless this index changes.
   */
  (prevProps, nextProps) => prevProps.item.index === nextProps.item.index,
);

4. Implement programmatic scrolling

react-procedural-scroller includes a scrollToIndex API, allowing you to scroll to any item programmatically. For example, you can use scrollToIndex to create a “Back to today!” button for the date scroller component from Step 2:

const { items, container, scrollToIndex } = useProceduralScroller(...)
<button
  onClick={() => {
    scrollToIndex({
      index: 0,
      block: 'center',
      behavior: 'smooth',
    });
  }}
>
  Back to today!
</button>

5. You're done!

Copying the examples above should result in a date scroller component like this:

Demo GIF


API Reference

Props

Return Values