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

@usefy/use-idle

v0.25.1

Published

A React hook that reports user inactivity after a timeout, with throttled activity listeners, visibility awareness, and SSR support

Readme


Overview

useIdle is part of the @usefy ecosystem — a collection of production-ready, TypeScript-first, SSR-safe React hooks. It tells you whether the user has gone inactive: it returns false while the user is active and flips to true once no listened activity (mouse, keyboard, touch, wheel, resize, tab focus) has occurred for a given timeout. The next activity flips it back to false. Use it for auto-away presence, idle timeouts / session expiry, pausing expensive work, or "are you still there?" prompts.

Features

  • Boolean-firstconst idle = useIdle(60_000) returns a plain boolean, matching the natural call site
  • Throttled activity — high-frequency events (mousemove, wheel, resize) reset the idle timer at most once every ~200ms (leading-edge), so React state never thrashes
  • Visibility-aware — returning to a backgrounded tab counts as activity; backgrounding the tab does not reset the timer, so the user is allowed to fall idle (the react-use/@mantine/hooks convention)
  • Configurable — customize the activity events, the initialState, and the target element
  • SSR-safe — no listeners are attached on the server; the hook returns initialState inertly, avoiding hydration mismatches
  • Concurrent- & StrictMode-safe — state is only set from event handlers and timers (never during render); every listener + timer is cleaned up on unmount or when the inputs change, so there are no leaks or double timers
  • TypeScript-first — full type inference and exported types (UseIdleOptions, IdleEventTarget, UseIdleReturn)
  • Tiny & tree-shakeable — zero dependencies, published as its own package

Installation

# npm
npm install @usefy/use-idle

# yarn
yarn add @usefy/use-idle

# pnpm
pnpm add @usefy/use-idle

Requires React 18 or 19 (peerDependencies: "react": "^18.0.0 || ^19.0.0").

Quick Start

import { useIdle } from "@usefy/use-idle";

function AwayBadge() {
  const idle = useIdle(60_000); // one minute
  return <span>{idle ? "💤 Away" : "🟢 Active"}</span>;
}

Log the user out after 5 minutes of inactivity:

import { useIdle } from "@usefy/use-idle";
import { useEffect } from "react";

function SessionGuard() {
  const idle = useIdle(5 * 60_000);
  useEffect(() => {
    if (idle) logout();
  }, [idle]);
  return null;
}

Only listen to keyboard activity, and start in the idle state:

import { useIdle } from "@usefy/use-idle";

const idle = useIdle(30_000, {
  events: ["keydown"],
  initialState: true,
});

API

useIdle(timeout?, options?): boolean

Returns true once the user has been inactive for timeout milliseconds, and false while active. Any listened activity marks the user active and restarts the timer.

| Parameter | Type | Description | | --------- | --------------- | ----------------------------------------------------------------------------------- | | timeout | number | Inactivity threshold in milliseconds before the user is considered idle. Default 60_000 (one minute). | | options | UseIdleOptions| Optional configuration (see below). |

UseIdleOptions

| Option | Type | Default | Description | | -------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | events | string[] | ["mousemove", "mousedown", "resize", "keydown", "touchstart", "wheel", "visibilitychange"] | Activity events that reset the idle timer. "visibilitychange" is always bound to document and handled specially. | | initialState | boolean | false | The initial idle state (also the SSR/inert value). Set true to start idle until the first activity. | | element | HTMLElement \| Document \| Window | window | The target the generic activity events attach to. "visibilitychange" is always attached to document, independent of this. |

Returns: booleantrue when idle, false when active. On the server (no window) it returns initialState.

Behavior notes

  • Throttling — activity is throttled with a leading-edge guard: the idle timer is reset at most once per ~200ms (the window is clamped to the timeout if you pick a smaller one). Because that window is at most the timeout, the timer never elapses during continuous activity, but rapid mousemove/wheel/resize bursts do not re-run state work on every event.
  • Visibilityvisibilitychange is routed through a dedicated handler on document. Returning to a visible tab (document.hidden === false) counts as activity and resets the timer; backgrounding the tab is not treated as activity, so the timer keeps running and the user falls idle naturally. Remove "visibilitychange" from events to opt out.
  • Changing timeout — passing a new timeout (or events/element) tears down and restarts the listeners and timer.

Exported helpers

import {
  useIdle,
  DEFAULT_IDLE_EVENTS,   // the default activity event list
  ACTIVITY_THROTTLE_MS,  // 200 — the leading-edge throttle window
  type UseIdleOptions,
  type IdleEventTarget,  // HTMLElement | Document | Window
  type UseIdleReturn,    // boolean
} from "@usefy/use-idle";

Browser Support

Works in every modern browser (Chrome, Edge, Firefox, Safari, and their mobile counterparts). In an environment without a window (SSR, tests without a DOM) no listeners are attached and the hook returns its inert initialState value without throwing.

Testing

📊 View Detailed Coverage Report (GitHub Pages) — 29 tests, 98% statement coverage.

License

MIT © mirunamu

This package is part of the usefy monorepo.