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

@ariefsn/svelte-use

v1.0.0

Published

Collection of reactive utility composables for Svelte 5 inspired by VueUse.

Downloads

143

Readme


Features

| | | | --------------------- | ----------------------------------------------------- | | ⚡ Svelte 5 Runes | Built for $state, $derived, $effect — no stores | | 🌲 Tree-shakable | Import only what you use | | 🔒 Fully typed | First-class TypeScript, no any | | 🌐 SSR safe | All browser APIs are guarded | | 📦 Zero deps | No runtime dependencies | | 🧹 Auto cleanup | Listeners removed on component destroy |


Installation

npm install @ariefsn/svelte-use
# or
pnpm add @ariefsn/svelte-use
# or
bun add @ariefsn/svelte-use

Requires Svelte 5 as a peer dependency.


Utilities

Animation

| Composable | Description | | --------------- | ----------------------------------------------- | | useAnimate | Reactive Web Animations API wrapper | | useParallax | Parallax effect based on pointer or device tilt | | useTransition | Animated numeric transitions with easing |

Async

| Composable | Description | | -------------- | --------------------------------------- | | useFetch | Reactive fetch with loading/error state | | useWebSocket | Reactive WebSocket with auto-reconnect |

Time

| Composable | Description | | ---------------- | -------------------------------------------- | | useInterval | Reactive interval counter | | useIntervalFn | Run a callback on an interval | | useNow | Reactive current Date | | useTimeout | Reactive timeout flag | | useTimeoutFn | Run a callback after a delay | | useTimeoutPoll | Poll a callback with timeout-based intervals | | useTimestamp | Reactive current timestamp (ms) |

State

| Composable | Description | | -------------- | ------------------------------------------- | | useToggle | Reactive boolean toggle | | useCounter | Reactive counter with inc/dec/reset | | usePrevious | Track previous value of any reactive getter | | useSorted | Reactive sorted copy of an array | | useCycleList | Cycle through a list reactively | | useCountdown | Countdown timer with start/stop/reset | | useTimeAgo | Human-readable relative time string |

Reactivity

| Composable | Description | | ------------- | ---------------------------- | | useDebounce | Debounce any reactive getter |

Browser – Keyboard & Scroll

| Composable | Description | | ---------------- | --------------------------------------------------------- | | useMagicKeys | Reactive keyboard state via Proxy — single keys or combos | | useKeyModifier | Track Ctrl/Shift/Alt/Meta state | | useScroll | Scroll position, direction, edge arrival | | useScrollLock | Lock/unlock body scroll |

Browser – Pointer & Drag

| Composable | Description | | ----------------- | -------------------------------------------------- | | useMouse | Viewport-relative pointer position | | useMousePressed | Detect mouse button press state | | useDraggable | Full-featured draggable with axis, bounds, handles |

Browser – Observers

| Composable | Description | | ------------------------- | ---------------------------------------------- | | useElementSize | Reactive element dimensions via ResizeObserver | | useIntersectionObserver | Visibility detection via IntersectionObserver | | useResizeObserver | Raw ResizeObserver with callback | | useMutationObserver | DOM mutation observation |

Browser – Sensors

| Composable | Description | | ---------------------- | ------------------------------------------------------ | | useIdle | Detect user idle state | | useNetwork | Network Information API (downlink, RTT, effectiveType) | | useGeolocation | Reactive geolocation via watchPosition | | useBreakpoints | Reactive responsive breakpoints | | useBrowserLocation | Reactive browser location (URL, hash, search) | | useNavigatorLanguage | Reactive navigator language | | useOnline | Reactive online/offline status | | usePageLeave | Detect when user leaves the page |

Browser – Storage

| Composable | Description | | ------------------- | --------------------------------------- | | useLocalStorage | Reactive localStorage with SSR safety | | useIndexedDB | Reactive IndexedDB with CRUD & querying | | useBase64 | Reactive Base64 encode/decode | | useObjectUrl | Reactive object URL from Blob/File | | useSessionStorage | Reactive sessionStorage with SSR safety |

Browser – Interaction

| Composable | Description | | ----------------- | ----------------------------------------- | | useClickOutside | Detect clicks outside an element | | useDropZone | Drag-and-drop zone with file/data support | | useElementHover | Detect hover state of an element | | useFocus | Reactive focus state of an element |

Performance

| Composable | Description | | --------------- | ---------------------------------- | | useFps | Reactive frames-per-second counter | | useThrottleFn | Throttle any function | | useDebounceFn | Debounce any function |

Virtualization

| Composable | Description | | ---------------- | -------------------------------- | | useVirtualList | Efficient virtual list rendering |

Web APIs

| Composable | Description | | ---------------------- | ----------------------------------- | | useClipboard | Reactive clipboard read/write | | useBattery | Reactive Battery Status API | | useSpeechRecognition | Reactive Web Speech Recognition API |


Composable Reference

useToggle

Reactive boolean toggle.

import { useToggle } from '@ariefsn/svelte-use';

const { value, toggle, set } = useToggle();
// value → false
toggle(); // value → true
set(false); // value → false

| Return | Type | Description | | -------- | ---------------------- | ------------------------- | | value | boolean (reactive) | Current boolean state | | toggle | () => void | Flips the value | | set | (v: boolean) => void | Sets the value explicitly |


useCounter

Reactive counter with increment, decrement, and reset.

import { useCounter } from '@ariefsn/svelte-use';

const { value, inc, dec, reset } = useCounter(0);
inc(); // value → 1
inc(5); // value → 6
dec(3); // value → 3
reset(); // value → 0

| Return | Type | Description | | ------- | -------------------------- | -------------------------------- | | value | number (reactive) | Current counter value | | inc | (delta?: number) => void | Increment by delta (default 1) | | dec | (delta?: number) => void | Decrement by delta (default 1) | | reset | () => void | Reset to initial value |


usePrevious

Tracks the previous value of any reactive getter. Returns undefined until the tracked value changes for the first time.

import { usePrevious } from '@ariefsn/svelte-use';

let count = $state(0);
const prev = usePrevious(() => count);
// prev() → undefined
count = 1;
// prev() → 0
count = 2;
// prev() → 1

| Parameter | Type | Description | | --------- | --------- | ----------------------------------- | | getter | () => T | Reactive getter function to observe |

Returns a () => T | undefined getter.


useDebounce

Delays a reactive value until the source stops changing for the specified duration.

import { useDebounce } from '@ariefsn/svelte-use';

let query = $state('');
const debounced = useDebounce(() => query, 500);
// debounced() updates only after 500 ms of inactivity

| Parameter | Type | Default | Description | | --------- | --------- | ------- | --------------------------- | | getter | () => T | — | Reactive getter to debounce | | delay | number | 300 | Delay in milliseconds |

Returns a () => T getter.


useLocalStorage

Reactive localStorage with SSR safety. Values are serialised with JSON.stringify / JSON.parse. Falls back to initial in non-browser environments or on parse errors.

import { useLocalStorage } from '@ariefsn/svelte-use';

const theme = useLocalStorage<'light' | 'dark'>('theme', 'light');
theme.set('dark'); // persists to localStorage
theme.value; // 'dark'

| Parameter | Type | Description | | --------- | -------- | ------------------------------------- | | key | string | localStorage key | | initial | T | Fallback when key is absent or in SSR |

| Return | Type | Description | | ------- | ---------------- | ---------------------------- | | value | T (reactive) | Current stored value | | set | (v: T) => void | Update and persist the value |


useIndexedDB

Reactive IndexedDB utility with full CRUD, querying, and filtering. SSR-safe — all operations are no-ops on the server. Values survive page refreshes and browser restarts.

import { useIndexedDB } from '@ariefsn/svelte-use';

interface Note {
	id?: number;
	text: string;
	done: boolean;
}

const db = useIndexedDB<Note>('my-app', 'notes');

// CRUD
await db.add({ text: 'Buy milk', done: false }); // returns generated key
await db.get(1); // Note | undefined
await db.getAll(); // Note[]
await db.update({ id: 1, text: 'Buy milk', done: true });
await db.remove(1);
await db.clear(); // delete all records

// Reactive state (updated automatically after every mutation)
db.items; // Note[]   — all records
db.loading; // boolean
db.error; // Error | null

// Filtering
const pending = await db.query((n) => !n.done); // Note[]

Options

| Parameter | Type | Default | Description | | ----------------------- | --------- | ------- | ------------------------------------- | | dbName | string | — | IndexedDB database name | | storeName | string | — | Object store name | | options.version | number | 1 | Schema version (increment to migrate) | | options.keyPath | string | 'id' | Primary key field name | | options.autoIncrement | boolean | true | Auto-generate numeric keys |

Returns

| Property / Method | Type | Description | | ----------------- | ----------------------------------- | ------------------------------------------------------------ | | items | T[] (reactive) | All stored records; refreshed after every mutation | | loading | boolean (reactive) | true while an async operation is in flight | | error | Error \| null (reactive) | Last error, or null | | add(record) | Promise<IDBValidKey \| undefined> | Insert record; returns generated key | | get(key) | Promise<T \| undefined> | Fetch single record by primary key | | getAll() | Promise<T[]> | Fetch all records and sync items | | update(record) | Promise<void> | Replace record (must include key field) | | remove(key) | Promise<void> | Delete record by primary key | | query(filter) | Promise<T[]> | Return records matching a predicate (doesn't modify items) | | clear() | Promise<void> | Delete all records |


useSorted

Returns a reactive sorted copy of an array. Never mutates the source.

import { useSorted } from '@ariefsn/svelte-use';

let items = $state([3, 1, 4, 1, 5]);
const sorted = useSorted(() => items);
// sorted() → [1, 1, 3, 4, 5]

const desc = useSorted(
	() => items,
	(a, b) => b - a
);

useCycleList

Cycle through a list reactively. Wraps around at both ends.

import { useCycleList } from '@ariefsn/svelte-use';

const cycle = useCycleList(['light', 'dark', 'system']);
cycle.state(); // → 'light'
cycle.next(); // → 'dark'
cycle.prev(); // → 'light'
cycle.setIndex(2);

useCountdown

Countdown timer with start/stop/reset.

import { useCountdown } from '@ariefsn/svelte-use';

const timer = useCountdown(60); // 60s at 1s intervals
timer.start();
timer.count(); // → 60, 59, …, 0
timer.isActive(); // → true
timer.stop();
timer.reset();

useTimeAgo

Reactive human-readable relative time string.

import { useTimeAgo } from '@ariefsn/svelte-use';

const ago = useTimeAgo(() => new Date('2024-01-01'));
ago(); // → "1 year ago"

useMagicKeys

Track any key or combination via a Proxy.

import { useMagicKeys } from '@ariefsn/svelte-use';

const keys = useMagicKeys();
keys['ctrl+s'](); // → true while Ctrl+S is held
keys['shift'](); // → true while Shift is held

useKeyModifier

Track a specific modifier key state.

import { useKeyModifier } from '@ariefsn/svelte-use';

const ctrl = useKeyModifier('ctrl'); // 'ctrl' | 'shift' | 'alt' | 'meta'
ctrl(); // → true while Ctrl is held

useScroll

Scroll position, direction flags, edge detection for any scrollable element or window.

import { useScroll } from '@ariefsn/svelte-use';

const scroll = useScroll(); // window
const elScroll = useScroll(() => myEl, { offset: { bottom: 20 } });

scroll.y(); // → number
scroll.isScrolling(); // → boolean
scroll.arrivedState.bottom(); // → boolean
scroll.directions.down(); // → boolean
scroll.scrollTo({ top: 0 });

useMouse

Tracks viewport-relative pointer position.

import { useMouse } from '@ariefsn/svelte-use';

const mouse = useMouse();
mouse.x(); // → number
mouse.y(); // → number
mouse.sourceType(); // → 'mouse' | 'touch' | null

useMousePressed

Detects whether any mouse button is held.

import { useMousePressed } from '@ariefsn/svelte-use';

const pressed = useMousePressed();
pressed(); // → boolean

useDraggable

Full-featured draggable with axis constraints, bounds, handles, and callbacks.

import { useDraggable } from '@ariefsn/svelte-use';

const drag = useDraggable(() => el, {
	axis: 'x',
	initialValue: { x: 100, y: 100 },
	onEnd: (pos) => console.log(pos)
});

drag.x(); // → number
drag.isDragging(); // → boolean
drag.style(); // → "transform: translate(100px, 0px);"

useElementSize

Reactively tracks element dimensions via ResizeObserver.

import { useElementSize } from '@ariefsn/svelte-use';

const size = useElementSize(() => el);
size.width(); // → number
size.height(); // → number

useIntersectionObserver

Viewport visibility detection.

import { useIntersectionObserver } from '@ariefsn/svelte-use';

const { isIntersecting, stop } = useIntersectionObserver(() => el, { threshold: 0.5 });
isIntersecting(); // → boolean

useResizeObserver

Raw ResizeObserver wrapper with automatic cleanup.

import { useResizeObserver } from '@ariefsn/svelte-use';

const { stop } = useResizeObserver(
	() => el,
	(entry) => {
		console.log(entry.contentRect.width);
	}
);

useMutationObserver

Observes DOM mutations on any node.

import { useMutationObserver } from '@ariefsn/svelte-use';

const { stop } = useMutationObserver(
	() => el,
	(mutations) => {
		for (const m of mutations) console.log(m.type);
	},
	{ childList: true, subtree: true }
);

useIdle

Detect user inactivity.

import { useIdle } from '@ariefsn/svelte-use';

const { isIdle, reset } = useIdle(5000); // idle after 5s
isIdle(); // → boolean

useNetwork

Reactive Network Information API.

import { useNetwork } from '@ariefsn/svelte-use';

const net = useNetwork();
net.effectiveType(); // → '4g' | '3g' | undefined
net.downlink(); // → Mbps | undefined
net.saveData(); // → boolean | undefined

useGeolocation

Reactive geolocation via watchPosition.

import { useGeolocation } from '@ariefsn/svelte-use';

const geo = useGeolocation({ enableHighAccuracy: true });
geo.coords()?.latitude; // → number | null
geo.error(); // → GeolocationPositionError | null
geo.isSupported(); // → boolean

useFetch

Reactive fetch wrapper with loading/error state.

import { useFetch } from '@ariefsn/svelte-use';

const { data, loading, error, execute } = useFetch<User[]>('/api/users');
// data() → User[] | null
// loading() → boolean
// error() → Error | null

useWebSocket

Reactive WebSocket with auto-reconnect.

import { useWebSocket } from '@ariefsn/svelte-use';

const ws = useWebSocket('wss://echo.example.com');
ws.send('hello');
ws.data(); // → last received message
ws.status(); // → 'OPEN' | 'CLOSED' | 'CONNECTING'

useAnimate

Reactive Web Animations API wrapper.

import { useAnimate } from '@ariefsn/svelte-use';

const { animate, stop } = useAnimate(() => el);
animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300 });

useParallax

Parallax effect based on pointer position or device tilt.

import { useParallax } from '@ariefsn/svelte-use';

const { tilt, roll } = useParallax(() => containerEl);
// tilt() → number  (−0.5 to 0.5)
// roll() → number  (−0.5 to 0.5)

useTransition

Animated numeric transitions with easing.

import { useTransition } from '@ariefsn/svelte-use';

let target = $state(0);
const animated = useTransition(() => target, { duration: 500 });
// animated() smoothly interpolates to target

useInterval

Reactive interval counter.

import { useInterval } from '@ariefsn/svelte-use';

const { counter, pause, resume } = useInterval(1000);
counter(); // → increments every second

useNow

Reactive current Date.

import { useNow } from '@ariefsn/svelte-use';

const now = useNow();
now(); // → Date (updated every second by default)

useTimestamp

Reactive current timestamp in milliseconds.

import { useTimestamp } from '@ariefsn/svelte-use';

const ts = useTimestamp();
ts(); // → number (ms since epoch)

useBreakpoints

Reactive responsive breakpoints.

import { useBreakpoints } from '@ariefsn/svelte-use';

const bp = useBreakpoints({ sm: 640, md: 768, lg: 1024 });
bp.lg(); // → true if viewport ≥ 1024px
bp.between('sm', 'lg')(); // → boolean

useClipboard

Reactive clipboard read/write.

import { useClipboard } from '@ariefsn/svelte-use';

const { text, copy, copied } = useClipboard();
copy('Hello!');
copied(); // → true for 1.5s after copy

useBattery

Reactive Battery Status API.

import { useBattery } from '@ariefsn/svelte-use';

const battery = useBattery();
battery.level(); // → 0–1
battery.charging(); // → boolean

useVirtualList

Efficient virtual list rendering for large datasets.

import { useVirtualList } from '@ariefsn/svelte-use';

const { list, containerProps, wrapperProps } = useVirtualList(items, { itemHeight: 40 });
// list() → only the visible slice of items

Developing

bun install
bun run dev

To run tests:

bun run test

Building & Publishing

# build the library
bun run build

# publish to npm
npm publish --access public

Links

  • 📦 npm: https://www.npmjs.com/package/@ariefsn/svelte-use
  • 🐙 GitHub: https://github.com/ariefsn/svelte-use

License

MIT