usehooks
A collection of modern, server-safe React hooks for browser APIs, storage, and UI interaction patterns from the ui.dev team.
Repository Health
Technical Analysis
usehooks (published as @uidotdev/usehooks) is a single-file, dependency-free collection of roughly three dozen React hooks covering the browser-API and UI-state problems most apps eventually reimplement themselves: battery status, geolocation, network state, clipboard access, local/session storage, intersection and resize observers, media queries, mouse/hover tracking, debouncing/throttling, and simple undo/redo history state.
Each hook is exported individually from one ESM entry point with no build step and no runtime dependencies beyond React itself (peer dependency on React 18+). Several of the browser-state hooks (useMediaQuery, useLocalStorage, useSessionStorage, useNetworkState, usePreferredLanguage, useVisibilityChange) are built on React’s useSyncExternalStore, making them safe under concurrent rendering rather than relying on ad hoc effect-driven state that can tear during concurrent updates. The project also publishes an experimental channel (@uidotdev/usehooks@experimental) with additional hooks like useFetch, useKeyPress, and useInterval that haven’t been promoted to the stable release.
What You Get
- ~37 standalone hooks covering storage (useLocalStorage, useSessionStorage), device/browser state (useBattery, useGeolocation, useNetworkState, useOrientation, usePreferredLanguage), and observers (useIntersectionObserver, useMeasure)
- Concurrent-safe implementations of the storage and media-query hooks built on React’s useSyncExternalStore, avoiding the tearing bugs older effect-based equivalents can hit
- Interaction hooks for common UI patterns: useClickAway, useHover, useLongPress, useMouse, useDebounce, useThrottle, useToggle
- State-container hooks that go beyond useState: useHistoryState (undo/redo), useMap, useSet, useQueue, useList, useObjectState
- Hand-written TypeScript declarations (index.d.ts) shipped alongside the ESM source, with no build/bundling step required to consume the package
- An experimental release channel (@uidotdev/usehooks@experimental) previewing additional hooks such as useFetch, useInterval, useKeyPress, and useEventListener before they’re promoted to stable
Common Use Cases
- Persisting UI state (theme, form drafts, filters) to localStorage/sessionStorage with automatic cross-tab sync via useLocalStorage/useSessionStorage
- Reacting to connectivity and device conditions (battery level, network type, online/offline) to adapt UI behavior on constrained devices
- Building interaction affordances like click-away dismissal, long-press, hover tracking, and lazy-load triggers via useIntersectionObserver
- Debouncing or throttling rapidly changing values (search input, scroll position, resize events) without hand-rolling timers in every component
- Adding undo/redo to editors or wizards with useHistoryState instead of building a custom reducer for history tracking
Under The Hood
Architecture The entire package is a single flat ESM file (index.js, ~1,370 lines) exporting roughly three dozen independent hook functions plus a handful of private, module-scoped helpers (isShallowEqual, throttle, dispatchStorageEvent, isPlainObject, isTouchEvent/isMouseEvent) shared by a few related hooks (useIdle reuses throttle, useLongPress reuses the event-type checks, the storage hooks share dispatchStorageEvent). There’s no shared runtime object graph or internal module boundary to reason about — each hook is self-contained and composed directly from React’s own primitives (useState, useEffect, useLayoutEffect, useSyncExternalStore, useReducer, useRef, useMemo, useCallback), so removing or changing one hook cannot break another; the only coupling risk is within the small set of shared private helpers.
Tech Stack The package has no runtime dependencies and a single peer dependency on react/react-dom >=18.0.0 (pinned to ^18.2.0 in devDependencies alongside @types/react ^18.2.20 and typescript ^5.1.6). It ships zero build output — package.json’s “exports” field points directly at the hand-authored index.js (ESM, “type”: “module”), and index.d.ts is a hand-written declaration file checked locally against a strict tsconfig.json (ESNext target/module, strict mode, allowJs) rather than emitted by a compiler step. The repository also contains a separate usehooks.com/ subdirectory — an Astro-based documentation site with a live demo per hook — that is entirely decoupled from the published npm package.
Code Quality No test files exist anywhere in the package source, and the repository has no CI configuration (no .github/workflows) to run type-checks, lint, or tests on push. Naming is consistent (useXxx hooks, camelCase helpers) and effect cleanup is handled correctly throughout (every addEventListener/observer pairs with a matching removal in the effect’s return function), but there is no automated way to verify the hand-written index.d.ts stays in sync with index.js, and no linter or formatter configuration is present at the package root. Error handling is inconsistent across hooks: useCounter and useWindowScroll throw explicit errors on invalid input, while useLocalStorage/useSessionStorage swallow JSON-parse failures behind a bare console.warn.
API Design The library’s core ergonomic choice is exposing several browser-state hooks (useLocalStorage, useSessionStorage, useMediaQuery, useNetworkState, usePreferredLanguage, useVisibilityChange) through useSyncExternalStore rather than the effect-plus-state pattern common in older hook collections, making them correctly tearing-safe under React 18’s concurrent renderer — a real correctness advantage over collections written before that API existed. Every hook is zero-config and independently importable with no provider or setup step, keeping the surface area small and predictable, though several hooks (useBattery, useGeolocation) are thin wrappers around their underlying Web APIs with limited abstraction beyond removing effect boilerplate, and SSR safety is handled ad hoc — some hooks simply throw (“useMediaQuery is a client-only hook”) when their server snapshot is invoked, leaving guard logic to the consumer.
Used by 14 apps in this directory
Anarlog
Note Taking · AI Assistants · Productivity
Anarlog is an open-source, local-first AI meeting notetaker that records, transcribes, and summarizes meetings entirely on your device — no cloud lock-in, no mandatory account, and every note saved as a plain markdown file you own forever.
ByteChef
Automation · AI Agents
Unified open-source platform for AI agent orchestration and workflow automation with 180+ connectors, MCP support, and durable execution.
Cap
Team Chat · Video Conferencing
Open source Loom alternative with GPU-accelerated recording, instant share links, AI summaries, and full self-hosting via Docker Compose.
DefGuard
Security · Networking · Authentication
Self-hosted secure remote access that unifies WireGuard VPN, identity management, and connection-level MFA in one open-source platform.
fountain-ink
Blogging
A self-hostable, decentralized blogging platform built on Lens Protocol — own your content, audience, and distribution forever.
Karakeep
Bookmarks Archiving
Self-hosted bookmark manager that captures links, notes, images, and PDFs with AI tagging, full-text search, and automatic archiving.
marimo
Developer Tools · Data Engineering
A reactive Python notebook that eliminates hidden state, runs reproducibly, and deploys as a web app or script — stored as pure Python, built for the AI era.
medusa
Ecommerce
The most flexible open-source commerce platform — build B2C, B2B, and marketplace applications with modular, composable commerce primitives.
nango
Developer Tools · Automation · Authentication
Build product integrations with AI using 800+ APIs — auth, proxy, and TypeScript functions on production-grade infrastructure.