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

@scroll-area/svelte

v0.1.0

Published

Small, composable scroll primitives for Svelte 5: a headless controller plus overridable track/fade/nav/hint components.

Readme

@scroll-area/svelte

Small, composable scroll primitives for Svelte 5 (Runes). SSR-safe, RTL-aware, zero-cost when idle, and fully overridable via snippets.

Install

npm install @scroll-area/svelte

Requires svelte@^5.0.0 as a peer dependency.

Quick start

<script lang="ts">
	import { ScrollArea } from '@scroll-area/svelte';
</script>

<ScrollArea>
	{#snippet children()}
		{#each items as item}
			<div class="w-64 shrink-0">{item.title}</div>
		{/each}
	{/snippet}
</ScrollArea>

ScrollArea is a pre-wired shell: overlay nav buttons, edge fades, and a scrollable track, all backed by a ScrollController. Every part of the UI is overridable via snippets (navigation, prevButton, nextButton), and you can drop down to the individual primitives (ScrollTrack, EdgeFade, EdgeHover, ScrollHint, NavButton) to build your own layout.

The composable pattern

Create a ScrollController outside any component to share scroll state with sibling UI (e.g. a header nav bar) without lifting it into a store:

<script lang="ts">
	import { ScrollController, ScrollTrack, EdgeFade } from '@scroll-area/svelte';
	const ctrl = new ScrollController({ itemsPerView: 5 });
</script>

<div class="flex justify-between">
	<h2>Featured</h2>
	<div>
		<button disabled={!ctrl.canScrollPrev} onclick={() => ctrl.scrollPrev()}>←</button>
		<button disabled={!ctrl.canScrollNext} onclick={() => ctrl.scrollNext()}>→</button>
	</div>
</div>

<div class="relative">
	<EdgeFade side="left" visible={ctrl.canScrollPrev} />
	<EdgeFade side="right" visible={ctrl.canScrollNext} />
	<ScrollTrack controller={ctrl} orientation="horizontal" class="gap-3 px-4">
		{#each items as item}
			<div class="w-[calc(100%/5.2)] shrink-0"><ItemCard {item} /></div>
		{/each}
	</ScrollTrack>
</div>

ScrollController

new ScrollController(options?: ScrollControllerOptions)

Options

| Option | Type | Default | Description | | -------------- | ------------------- | -------------- | ------------------------------------ | | orientation | ScrollOrientation | 'horizontal' | Axis or axes to scroll | | step | number | — | Explicit px per step | | itemsPerView | number | — | step = containerSize / itemsPerView | | behavior | ScrollBehavior | 'smooth' | Forwarded to element.scrollTo() | | rtl | boolean | false | Initial RTL; auto-updated from DOM |

Reactive state

| Property | Type | Description | | ------------------ | --------- | --------------------------------------- | | canScrollNext | boolean | Forward scroll possible | | canScrollPrev | boolean | Backward scroll possible | | isOverflowing | boolean | Content overflows the container | | isHoverScrolling | boolean | A startScrolling() loop is running | | scrollPosition | {x, y} | Each axis: { offset, max, progress } | | rtl | boolean | Reactive; updated by MutationObserver |

Methods

| Method | Description | | -------------------------- | ------------------------------------------------- | | mount(el) | Attaches to a scroll container (called by ScrollTrack) | | destroy() | Tears down all listeners/observers/loops; idempotent | | scrollNext() / scrollPrev() | One step forward/backward; no-op at the boundary | | scrollTo(target) | Scroll to a child index or HTMLElement | | startScrolling(options) | Begin a continuous rAF scroll loop (idempotent) | | stopScrolling() | Stop the loop; safe to call when nothing is running | | watchScroll(callback) | Subscribe to scroll percentage; returns a cleanup fn |

startScrolling / stopScrolling

Used by hover-zone or long-press UI. The loop accelerates from minSpeed to maxSpeed over ~60 frames. isHoverScrolling is true while running.

<EdgeHover side="prev" enabled={ctrl.canScrollPrev} controller={ctrl}>
	<EdgeFade side="left" visible={ctrl.canScrollPrev}>
		<ScrollHint side="left" visible={!ctrl.isHoverScrolling} />
	</EdgeFade>
</EdgeHover>

Reactive RTL

The controller watches the dir attribute on the scroll element and every ancestor via MutationObserver. Flipping dir anywhere in that chain instantly updates ctrl.rtl, boundary detection, and navigation — no reload required.

Vertical orientation — important

ScrollArea / ScrollTrack fill their parent (h-full internally). The parent must have an explicit height, or the container collapses to 0.

<!-- ✓ Correct: parent has an explicit height -->
<div class="h-64">
	<ScrollArea orientation="vertical">...</ScrollArea>
</div>

<!-- ✗ Broken: no height constraint, ScrollTrack collapses -->
<ScrollArea orientation="vertical">...</ScrollArea>

Exports

| Export | Role | | -------------------- | --------------------------------------------------------------------------------- | | ScrollController | All scroll state and logic. Create outside any component to share state. | | ScrollTrack | The scrollable surface. Binds the controller to a DOM element. | | EdgeFade | Gradient edge indicator. Accepts children for nav buttons and scroll hints. | | EdgeHover | Hover-to-scroll wrapper; calls startScrolling/stopScrolling on pointer enter/leave. | | ScrollHint | Animated hint nudging toward hidden content. | | ScrollArea | Pre-wired shell with overlay navigation, all UI overridable via snippets. | | NavButton | Default orientation-aware nav button used internally by ScrollArea. | | Types | ScrollAreaProps, ScrollControllerOptions, ScrollScrollingOptions, ScrollPosition, AxisScrollPosition, ScrollTarget, NavButtonProps, EdgeFadeProps, EdgeHoverProps, ScrollHintProps, WatchScrollCleanup | | Enums | ScrollBehavior, ScrollDirection, ScrollOrientation, EdgeSide | | Constants | DEFAULT_STEP_RATIO, DEFAULT_SCROLL_BEHAVIOR, SCROLL_BOUNDARY_TOLERANCE | | Low-level utils | getHorizontalPosition, getVerticalPosition, getScrollPosition, canScrollHorizontalNext, canScrollHorizontalPrev, canScrollVerticalNext, canScrollVerticalPrev, isOverflowingHorizontal, isOverflowingVertical, scrollHorizontalByDelta, scrollVerticalByDelta, scrollToTarget, resolveStep, detectRtlFromDom, debounce |

The low-level utils, constants, and types are exported so you can build a custom scroll UI (or a different feature entirely) on top of the same primitives instead of duplicating them.

Icons

Default nav/hint icons come from lucide-svelte, a direct dependency of this package. Override any icon by passing your own content via the relevant children snippet — see NavButtonProps, ScrollHintProps.

Example

A full runnable demo covering every export lives in examples/svelte at the repo root — see its own README.md for how to run it.

License

MIT