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

littkk

v3.0.0

Published

A more powerful and flexible headroom library that hides site headers or footers when scrolling down and reveals them again when scrolling up.

Readme

Littkk · Size npm version PRs Welcome GitHub license jsDocs.io typescript

Hide, show, and stack elements on scroll — works on multiple elements, in any direction, with no classes, no config files, and no framework adapters. Automatically recalculates on layout shifts!

Just add a data-scroll-top (or bottom / left / right) attribute and call littkk()!

Online Demos

https://littkk.tsdk.dev

Attributes

There are three modes, determined by the value of the attribute.

Note on Positioning: Elements managed by littkk should be position: fixed | sticky | absolute. If you leave an element as static, littkk will automatically apply position: sticky for you!

Hide mode — empty value

Slides the element out of the viewport on scroll down, and back in on scroll up. Hide-mode elements contribute their dimensions to the layout stack while visible.

<header data-scroll-top></header>
<footer data-scroll-bottom></footer>
<nav data-scroll-left></nav>
<aside data-scroll-right></aside>

| Direction | Attribute | Behavior | | --------- | -------------------- | ---------------------------- | | Up | data-scroll-top | slides up out of viewport | | Down | data-scroll-bottom | slides down out of viewport | | Left | data-scroll-left | slides left out of viewport | | Right | data-scroll-right | slides right out of viewport |

Stack mode — ="stack"

The element never hides. Instead, its position is automatically calculated as the sum of the heights (or widths) of all visible Hide/Stack mode elements above it in the DOM. If a Hide mode element scrolls out of view, the Stack elements below it smoothly slide up to take its place.

<header data-scroll-top>Header</header>

<nav data-scroll-top="stack">Sub-Navigation</nav>

Distance mode — CSS value

The element is never hidden. Instead its CSS edge property (top / bottom / left / right) transitions to the given value on scroll down, and reverts on scroll up. Bare numbers are treated as px. Any CSS unit is accepted.

<div data-scroll-top="0"></div>

<div data-scroll-top="1rem"></div>

<div data-scroll-bottom="0" data-scroll-right="0"></div>

Shared attributes

| Attribute | Values | Default | Applies to | | --------------- | ------ | ------------------------ | -------------- | | data-duration | ms | 300 | all modes | | data-delay | ms | 0 | hide, distance | | data-trigger | 0 - 1 | 0.67 | hide, distance | | data-offset | px | auto from computed style | hide mode only |

data-trigger — Fraction of the element's size that must be scrolled past before hiding triggers. (e.g., 0.5 means scroll half the element's height).

data-delay — ms to wait after scroll stops before executing. Scrolling again resets the timer. Showing is always immediate.

data-offset — overrides the auto-computed slide distance. Useful when getComputedStyle().top/bottom/left/right is unreliable, e.g. with inset shorthand or a pre-existing transform.

Options

littkk({
  scrollTarget: "#my-div", // window (default), HTMLElement, or CSS selector
  threshold: 5, // min px delta before direction change triggers show/hide. Default: 5
  showAtTop: true, // force-show all elements when scroll position reaches 0. Default: true
  enable: true, // enable or disable the controller. Default: true
  triggerRatio: 0.67, // default scroll trigger fraction for all elements. Default: 0.67
});

Return

export interface LittkkController {
  /** Re-scan DOM and sync new elements to current scroll state. */
  refresh: () => void;
  /** Remove scroll & resize listeners and reset all element styles. */
  destroy: () => void;
  /** Dynamically enable or disable the scroll behavior. */
  setEnable: (enable: boolean) => void;
}

(Note: littkk utilizes ResizeObserver internally, meaning if your elements change height due to window resizing or text wrapping, the stack calculations will automatically refresh!)

HTML Example

<header data-scroll-top style="height: 60px;">Main Header</header>

<nav data-scroll-top="stack" style="height: 40px;">Sticky Navigation</nav>

<div data-scroll-top="stack">Action Bar</div>

<script type="module">
  import { littkk } from "littkk";
  littkk();
</script>

React

import { useEffect } from "react";
import { littkk, LittkkOptions } from "littkk";

function useLittkk(options?: LittkkOptions) {
  useEffect(() => {
    const ctrl = littkk(options);
    return () => ctrl.destroy();
  }, []);
}
export default function App() {
  useLittkk();

  return (
    <>
      <header data-scroll-top>...</header>

      <main data-scroll-top="stack">...</main>
    </>
  );
}

For a scrollable container, pass the ref as scrollTarget. Call ctrl.refresh() after conditionally rendered elements mount.

export default function Feed() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!containerRef.current) return;
    const ctrl = littkk({ scrollTarget: containerRef.current });
    return () => ctrl.destroy();
  }, []);

  return (
    <div ref={containerRef} style={{ height: "100vh", overflowY: "auto" }}>
      <header data-scroll-top>...</header>
    </div>
  );
}

Vue

<script setup>
import { onUnmounted } from "vue";
import { littkk } from "littkk";

const ctrl = littkk();
onUnmounted(() => ctrl.destroy());
</script>

<template>
  <header data-scroll-top>...</header>
  <main data-scroll-top="stack">...</main>
</template>

For a scrollable container:

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import { littkk } from "littkk";

const containerRef = ref(null);
let ctrl;

onMounted(() => {
  ctrl = littkk({ scrollTarget: containerRef.value });
});
onUnmounted(() => ctrl?.destroy());
</script>

<template>
  <div ref="containerRef" style="height: 100vh; overflow-y: auto;">
    <header data-scroll-top>...</header>
  </div>
</template>

Call ctrl.refresh() after conditionally rendered elements mount — e.g. in a watch or after an async operation.

Projects You May Also Be Interested In

  • xior - A tiny but powerful fetch wrapper with plugins support and axios-like API
  • tsdk - Type-safe API development CLI tool for TypeScript projects
  • broad-infinite-list - ⚡ High performance and Bidirectional infinite scrolling list component for React and Vue3

Reporting Issues

Found an issue? Please feel free to create issue

Support

If you find this project helpful, consider buying me a coffee.