# ReactUse (@reactuses/core)
ReactUse is a comprehensive collection of 100+ essential React Hooks for building modern React applications, inspired by VueUse. It provides production-ready, tree-shakable hooks organized into four categories — Browser, State, Element, and Effect — covering everything from clipboard access and media queries to drag-and-drop, intersection observation, and async effects. The library is fully typed with TypeScript, SSR-compatible for use with Next.js and Remix, and ships with an optional MCP (Model Context Protocol) server for AI-powered hook discovery.
At its core, the library follows a consistent design philosophy: hooks accept `BasicTarget` values (refs, direct elements, or selector functions) for flexible DOM targeting; browser-environment checks prevent SSR crashes; event listeners and observers are cleaned up automatically; and stable function references via `useEvent`/`useLatest` eliminate common infinite-render pitfalls. Version 6.3.1 (the current release) requires React 19 as a peer dependency and supports concurrent mode.
---
## Installation
```bash
npm i @reactuses/core
# or
pnpm add @reactuses/core
# or
yarn add @reactuses/core
```
---
## State Hooks
### useToggle — toggle a boolean on/off
Manages a boolean value and returns a toggler that optionally accepts a forced value.
```tsx
import { useToggle } from "@reactuses/core";
function ToggleDemo() {
const [on, toggle] = useToggle(false);
return (
Status: {on ? "ON" : "OFF"}
);
}
```
---
### useBoolean — boolean state with named helpers
Returns an object with `setTrue`, `setFalse`, and `toggle` for ergonomic boolean state management.
```tsx
import { useBoolean } from "@reactuses/core";
function Modal() {
const { value: isOpen, setTrue: open, setFalse: close, toggle } = useBoolean(false);
return (
<>
{isOpen && (
Modal content
)}
>
);
}
```
---
### useCounter — numeric counter with bounds
Provides increment, decrement, set, and reset with optional min/max clamping.
```tsx
import { useCounter } from "@reactuses/core";
function CounterDemo() {
const [count, setCount, inc, dec, reset] = useCounter(0, 10, 0);
// max=10, min=0
return (
Count: {count}
);
}
```
---
### useMap — reactive Map data structure
Wraps `Map` with reactive state and convenience methods: `set`, `get`, `remove`, `has`, `clear`, `reset`.
```tsx
import { useMap } from "@reactuses/core";
function MapDemo() {
const { map, set, get, remove, has, clear, size } = useMap([
["apples", 5],
["oranges", 3],
]);
return (
Items: {size}
Apples: {get("apples")}
{Array.from(map.entries()).map(([k, v]) => (
{k}: {v}
))}
);
}
```
---
### useLocalStorage — persistent state synced to localStorage
Persists state across page reloads and syncs changes across browser tabs in real time.
```tsx
import { useLocalStorage } from "@reactuses/core";
interface UserPrefs {
theme: "light" | "dark";
fontSize: number;
}
function Settings() {
const [prefs, setPrefs] = useLocalStorage("user-prefs", {
theme: "light",
fontSize: 16,
}, {
listenToStorageChanges: true, // sync across tabs (default: true)
onError: (err) => console.error("Storage error:", err),
});
return (
Theme: {prefs?.theme}
);
}
```
---
### useSessionStorage — session-scoped persistent state
Identical API to `useLocalStorage` but backed by `sessionStorage` (cleared when tab closes).
```tsx
import { useSessionStorage } from "@reactuses/core";
function WizardStep() {
const [step, setStep] = useSessionStorage("wizard-step", 1);
return (
Current step: {step}
);
}
```
---
### useDebounce — debounce a reactive value
Returns a debounced copy of a value that only updates after the specified delay has passed without changes.
```tsx
import { useDebounce } from "@reactuses/core";
import { useState } from "react";
function SearchInput() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 400);
// debouncedQuery only changes 400ms after the user stops typing
useEffect(() => {
if (debouncedQuery) fetchResults(debouncedQuery);
}, [debouncedQuery]);
return setQuery(e.target.value)} />;
}
```
---
### useDebounceFn — debounce a callback function
Returns a `{ run, cancel, flush }` object wrapping a debounced version of the provided function.
```tsx
import { useDebounceFn } from "@reactuses/core";
function AutoSave({ onSave }: { onSave: (data: string) => void }) {
const { run: save, cancel, flush } = useDebounceFn(onSave, 1000);
return (
);
}
```
---
### useThrottle — throttle a reactive value
Returns a throttled copy of a value that updates at most once per specified interval.
```tsx
import { useThrottle } from "@reactuses/core";
import { useState } from "react";
function ScrollTracker() {
const [scrollY, setScrollY] = useState(0);
const throttledY = useThrottle(scrollY, 100); // update at most every 100ms
useEffect(() => {
const handler = () => setScrollY(window.scrollY);
window.addEventListener("scroll", handler);
return () => window.removeEventListener("scroll", handler);
}, []);
return
Throttled scroll position: {throttledY}px
;
}
```
---
### useThrottleFn — throttle a callback function
Wraps a function to limit execution frequency, returning `{ run, cancel, flush }`.
```tsx
import { useThrottleFn } from "@reactuses/core";
function RateLimitedButton({ onSubmit }: { onSubmit: () => void }) {
const { run: submit } = useThrottleFn(onSubmit, 2000);
// onSubmit can only be called at most once every 2 seconds
return ;
}
```
---
### usePrevious — access previous render's value
Returns the value from the previous render cycle. Returns `undefined` on first render.
```tsx
import { usePrevious } from "@reactuses/core";
function ValueTracker({ value }: { value: number }) {
const prev = usePrevious(value);
return (
Changed from {prev ?? "—"} → {value}
{prev !== undefined && value > prev && " ↑"}
{prev !== undefined && value < prev && " ↓"}
);
}
```
---
### useSetState — partial state updates like class components
Merges partial updates into existing state, similar to `this.setState` in class components.
```tsx
import { useSetState } from "@reactuses/core";
function Form() {
const [state, setState] = useSetState({
username: "",
email: "",
age: 0,
loading: false,
});
const handleSubmit = async () => {
setState({ loading: true });
await submitForm(state);
setState({ loading: false });
};
return (
);
}
```
---
### useDisclosure — manage open/closed UI state
Manages open/closed state for modals, drawers, and dropdowns with `open`, `close`, and `toggle` helpers.
```tsx
import { useDisclosure } from "@reactuses/core";
function DrawerDemo() {
const { isOpen, open, close, toggle } = useDisclosure(false);
return (
<>
Drawer content here
>
);
}
```
---
### useCycleList — cycle through a list of values
Steps through an array of values forward and backward, with the current value and navigation functions.
```tsx
import { useCycleList } from "@reactuses/core";
const THEMES = ["light", "dark", "high-contrast", "solarized"] as const;
function ThemeSwitcher() {
const { state: theme, next, prev } = useCycleList(THEMES);
return (
Current theme: {theme}
);
}
```
---
### useLatest — always-current ref for callbacks
Returns a `MutableRefObject` that always holds the latest value of its argument without causing re-renders. Use inside `useCallback`/`useEffect` to avoid stale closures.
```tsx
import { useLatest } from "@reactuses/core";
import { useEffect } from "react";
function Logger({ onData }: { onData: (v: string) => void }) {
const onDataRef = useLatest(onData);
useEffect(() => {
const id = setInterval(() => {
// Always calls the latest onData without adding it to deps
onDataRef.current(new Date().toISOString());
}, 1000);
return () => clearInterval(id);
}, []); // no re-subscription when onData changes
return
Logging every second…
;
}
```
---
### useEvent — stable callback reference
Creates a stable function wrapper whose identity never changes between renders while always invoking the latest version of the provided function.
```tsx
import { useEvent } from "@reactuses/core";
function ChatInput({ onSend }: { onSend: (msg: string) => void }) {
const [text, setText] = useState("");
// stableSubmit has a stable identity — safe to pass to child components
// without breaking memoization
const stableSubmit = useEvent(() => {
onSend(text);
setText("");
});
return (
setText(e.target.value)} />
{/* memo-safe */}
);
}
```
---
## Browser Hooks
### useDarkMode — dark mode with localStorage persistence
Reads, writes, and persists the dark/light mode preference. Applies a class to `` and stores the preference in localStorage.
```tsx
import { useDarkMode } from "@reactuses/core";
function ThemeToggle() {
const [isDark, setIsDark] = useDarkMode(false, {
storageKey: "app-dark-mode",
selector: "html",
attribute: "class",
// Add this script to to prevent flash of wrong theme on SSR:
// localStorage.getItem("app-dark-mode") === "dark"
// ? document.documentElement.classList.add("dark")
// : document.documentElement.classList.remove("dark")
});
return (
);
}
```
---
### useColorMode — multi-theme color mode management
Extends dark mode to support arbitrary named color modes (e.g., light, dark, blue, sepia), persisted to storage and applied as classes or attributes on a DOM element.
```tsx
import { useColorMode } from "@reactuses/core";
type AppMode = "light" | "dark" | "blue" | "sepia";
function ThemePicker() {
const [mode, setMode, cycleMode] = useColorMode({
modes: ["light", "dark", "blue", "sepia"],
defaultValue: "light",
storageKey: "app-color-mode",
selector: "html",
attribute: "class",
});
return (
Current: {mode}
{(["light", "dark", "blue", "sepia"] as AppMode[]).map(m => (
))}
);
}
```
---
### useMediaQuery — reactive CSS media query
Tracks whether a CSS media query currently matches, re-evaluating on viewport changes. Accepts an optional default value for SSR hydration safety.
```tsx
import { useMediaQuery } from "@reactuses/core";
function ResponsiveLayout() {
const isMobile = useMediaQuery("(max-width: 767px)", false);
const isTablet = useMediaQuery("(min-width: 768px) and (max-width: 1023px)", false);
const prefersReducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)", false);
return (
);
}
```
---
### useIdle — detect user inactivity
Detects when the user has been idle for a specified duration, watching mouse, keyboard, pointer, and visibility events.
```tsx
import { useIdle } from "@reactuses/core";
function AutoLogout() {
const isIdle = useIdle(5 * 60 * 1000); // 5 minutes
useEffect(() => {
if (isIdle) {
alert("Session expired due to inactivity.");
logout();
}
}, [isIdle]);
return
;
}
```
---
### useTitle — set the document title
Sets `document.title` reactively and optionally restores the previous title on unmount.
```tsx
import { useTitle } from "@reactuses/core";
function ProductPage({ product }: { product: { name: string } }) {
useTitle(`${product.name} — My Store`, {
restoreOnUnmount: true, // restore previous title when component unmounts
});
return
{product.name}
;
}
```
---
### useFavicon — dynamically change the page favicon
Swaps the `` href reactively.
```tsx
import { useFavicon } from "@reactuses/core";
function NotificationBadge({ unread }: { unread: number }) {
useFavicon(unread > 0 ? "/favicon-badge.ico" : "/favicon.ico");
return {unread} unread;
}
```
---
### useFullscreen — element fullscreen API
Enters/exits fullscreen for any element, tracking the current state and checking browser support.
```tsx
import { useFullscreen } from "@reactuses/core";
import { useRef } from "react";
function VideoPlayer() {
const videoRef = useRef(null);
const [isFullscreen, { enterFullscreen, exitFullscreen, isEnabled }] =
useFullscreen(videoRef, {
onEnter: () => console.log("Entered fullscreen"),
onExit: () => console.log("Exited fullscreen"),
});
return (
{isEnabled && (
)}
);
}
```
---
### useBroadcastChannel — cross-tab messaging
Creates a BroadcastChannel for sending and receiving messages across browser tabs/windows of the same origin.
```tsx
import { useBroadcastChannel } from "@reactuses/core";
type Message = { type: "LOGOUT" | "REFRESH_TOKEN"; payload?: string };
function TabSync() {
const { isSupported, data, post, isClosed } = useBroadcastChannel({
name: "app-sync",
});
useEffect(() => {
if (data?.type === "LOGOUT") performLogout();
if (data?.type === "REFRESH_TOKEN") setToken(data.payload!);
}, [data]);
if (!isSupported) return null;
return (
);
}
```
---
### useEventSource — Server-Sent Events (SSE)
Connects to an SSE endpoint and delivers the latest message data, managing connection lifecycle automatically.
```tsx
import { useEventSource } from "@reactuses/core";
function LiveFeed() {
const { data, status, close } = useEventSource("/api/events", {
withCredentials: true,
});
return (
Connection: {status}
Latest event: {data}
);
}
```
---
### usePermission — query browser permission status
Queries the Permissions API for a given permission name, returning its current state (`granted`, `denied`, or `prompt`).
```tsx
import { usePermission } from "@reactuses/core";
function CameraButton() {
const cameraState = usePermission("camera");
if (cameraState === "denied") return
Camera access denied.
;
return (
);
}
```
---
## Element Hooks
### useHover — detect element hover state
Returns `true` while the pointer is over the target element, using `pointerenter`/`pointerleave` events.
```tsx
import { useHover } from "@reactuses/core";
import { useRef } from "react";
function HoverCard() {
const ref = useRef(null);
const isHovered = useHover(ref);
return (
{isHovered ? "Hovering!" : "Hover over me"}
);
}
```
---
### useClickOutside — detect clicks outside an element
Calls a handler when a click or touch occurs outside the target element. Accepts an optional `enabled` flag.
```tsx
import { useClickOutside } from "@reactuses/core";
import { useRef, useState } from "react";
function Dropdown() {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useClickOutside(ref, () => setOpen(false), open);
return (
{open && (
Item 1
Item 2
Item 3
)}
);
}
```
---
### useElementSize — track element dimensions
Uses `ResizeObserver` to reactively report an element's `width` and `height`.
```tsx
import { useElementSize } from "@reactuses/core";
import { useRef } from "react";
function ResponsiveChart() {
const containerRef = useRef(null);
const [width, height] = useElementSize(containerRef);
return (
);
}
```
---
### useElementBounding — reactive bounding rect
Returns the element's `DOMRect` properties (`top`, `left`, `right`, `bottom`, `width`, `height`, `x`, `y`), updated on scroll and resize.
```tsx
import { useElementBounding } from "@reactuses/core";
import { useRef } from "react";
function TooltipAnchor() {
const ref = useRef(null);
const { top, left, width } = useElementBounding(ref);
return (
<>
Tooltip!
>
);
}
```
---
### useElementVisibility — is element visible in viewport
Returns a boolean indicating whether the element is currently visible in the viewport using `IntersectionObserver`.
```tsx
import { useElementVisibility } from "@reactuses/core";
import { useRef } from "react";
function LazySection() {
const ref = useRef(null);
const isVisible = useElementVisibility(ref);
return (
);
}
```
---
### useDraggable — draggable elements
Makes an element draggable using pointer events, supporting handles, containers, and positional constraints.
```tsx
import { useDraggable } from "@reactuses/core";
import { useRef } from "react";
function DraggablePanel() {
const panelRef = useRef(null);
const containerRef = useRef(null);
const [x, y, isDragging, setPosition] = useDraggable(panelRef, {
containerElement: containerRef,
initialValue: { x: 50, y: 50 },
onStart: (pos) => { console.log("drag started", pos); return true; },
onEnd: (pos) => console.log("drag ended", pos),
});
return (
Drag me
);
}
```
---
### useMouse — reactive cursor position
Tracks the cursor's position (`x`, `y`) relative to the page and optionally a specific element.
```tsx
import { useMouse } from "@reactuses/core";
function MouseTracker() {
const { x, y, sourceType } = useMouse();
return (
Cursor: ({x}, {y}) via {sourceType}
{x}, {y}
);
}
```
---
### useScroll — reactive scroll position of an element
Tracks the scroll `x` and `y` of any scrollable element (or the window).
```tsx
import { useScroll } from "@reactuses/core";
import { useRef } from "react";
function ScrollableList() {
const listRef = useRef(null);
const { x, y, arrivedState, directions } = useScroll(listRef);
return (
);
}
```
---
### useScrollIntoView — programmatically scroll element into view
Returns a function to smoothly scroll a target element into the viewport.
```tsx
import { useScrollIntoView } from "@reactuses/core";
import { useRef } from "react";
function JumpToSection() {
const sectionRef = useRef(null);
const scrollIntoView = useScrollIntoView(sectionRef, {
behavior: "smooth",
block: "start",
});
return (
<>
Target Section
>
);
}
```
---
### useIntersectionObserver — observe element intersection
Low-level `IntersectionObserver` hook that fires a callback with intersection entries when the target enters or exits a root.
```tsx
import { useIntersectionObserver } from "@reactuses/core";
import { useRef, useState } from "react";
function AnimatedCard() {
const ref = useRef(null);
const [visible, setVisible] = useState(false);
useIntersectionObserver(
ref,
([entry]) => setVisible(entry.isIntersecting),
{ threshold: 0.3, rootMargin: "0px 0px -50px 0px" }
);
return (
Current size: {Math.round(size.width)}×{Math.round(size.height)}
>
);
}
```
---
### useMutationObserver — observe DOM mutations
Fires a callback when the target element's children, attributes, or text content change.
```tsx
import { useMutationObserver } from "@reactuses/core";
import { useRef, useState } from "react";
function DOMWatcher() {
const ref = useRef(null);
const [mutationCount, setMutationCount] = useState(0);
useMutationObserver(
ref,
(mutations) => setMutationCount(c => c + mutations.length),
{ childList: true, subtree: true, attributes: true }
);
return (
Watched element
Mutations detected: {mutationCount}
);
}
```
---
### useLongPress — detect long press gestures
Attaches handlers for detecting long presses on both mouse and touch devices. Returns event handler props to spread onto an element.
```tsx
import { useLongPress } from "@reactuses/core";
function ContextButton() {
const handlers = useLongPress(
(e) => {
console.log("Long pressed!", e);
showContextMenu(e);
},
{ delay: 500, isPreventDefault: true }
);
return (
);
}
```
---
### useDropZone — file/element drop zone
Tracks drag-over state and fires callbacks on file drop for a target element.
```tsx
import { useDropZone } from "@reactuses/core";
import { useRef, useState } from "react";
function FileDropZone() {
const dropRef = useRef(null);
const [files, setFiles] = useState([]);
const { isOverDropZone } = useDropZone(dropRef, {
onDrop: (droppedFiles) => setFiles(droppedFiles ?? []),
dataTypes: ["image/png", "image/jpeg", "application/pdf"],
});
return (
{isOverDropZone ? "Release to drop" : "Drag files here"}
{files.map(f =>
{f.name} ({(f.size / 1024).toFixed(1)} KB)
)}
);
}
```
---
### useActiveElement — track focused element
Returns the currently focused `document.activeElement`, updating as focus moves.
```tsx
import { useActiveElement } from "@reactuses/core";
function FocusTracker() {
const activeEl = useActiveElement();
return (
Focused: {activeEl?.tagName?.toLowerCase() ?? "none"} — {(activeEl as HTMLInputElement)?.name}
);
}
```
---
### useTextSelection — get selected text
Returns the current text `selection` and `text` string whenever the user selects text in the document.
```tsx
import { useTextSelection } from "@reactuses/core";
function SelectionHighlighter() {
const { text, rects } = useTextSelection();
return (
ReactUse makes it easy to build interactive React applications with
well-designed, production-ready hooks.
{text && (
Selected: "{text}"
)}
);
}
```
---
## Effect Hooks
### useMount — run effect on mount only
Executes a callback exactly once when the component mounts. Cleaner alternative to `useEffect(fn, [])`.
```tsx
import { useMount } from "@reactuses/core";
function DataLoader({ id }: { id: string }) {
const [data, setData] = useState(null);
useMount(() => {
fetchData(id).then(setData);
analytics.track("page_view", { id });
});
return data ? : ;
}
```
---
### useUnmount — run effect on unmount only
Executes a cleanup callback when the component is about to unmount.
```tsx
import { useUnmount } from "@reactuses/core";
function VideoPlayer({ streamId }: { streamId: string }) {
const playerRef = useRef(null);
useMount(() => { playerRef.current = initPlayer(streamId); });
useUnmount(() => {
playerRef.current?.destroy();
console.log("Player destroyed");
});
return ;
}
```
---
### useInterval — managed setInterval
Wraps `setInterval` with pause/resume controls and automatic cleanup.
```tsx
import { useInterval } from "@reactuses/core";
import { useState } from "react";
function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const { isActive, pause, resume } = useInterval(
() => setSeconds(s => s + 1),
1000,
{ immediate: false }
);
return (
{seconds}s
);
}
```
---
### useEventListener — attach DOM event listeners
Attaches and cleans up an event listener on any target (window, document, element, or custom EventTarget).
```tsx
import { useEventListener } from "@reactuses/core";
import { useState } from "react";
function KeyboardShortcuts() {
const [lastKey, setLastKey] = useState("");
useEventListener("keydown", (e: KeyboardEvent) => {
if (e.ctrlKey && e.key === "s") {
e.preventDefault();
saveDocument();
}
setLastKey(e.key);
});
return
Last key pressed: {lastKey}
;
}
```
---
### useAsyncEffect — async-safe useEffect
Runs an async function as an effect, handling cleanup gracefully without the "can't update unmounted component" warning.
```tsx
import { useAsyncEffect } from "@reactuses/core";
import { useState } from "react";
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
useAsyncEffect(
async () => {
try {
const data = await fetch(`/api/users/${userId}`).then(r => r.json());
setUser(data);
} catch (err) {
setError(err as Error);
}
},
async () => { /* cleanup: cancel ongoing requests here */ },
[userId]
);
if (error) return
Error: {error.message}
;
if (!user) return
Loading…
;
return
{user.name}
;
}
```
---
### useDeepCompareEffect — effect with deep equality check
Like `useEffect` but performs deep equality comparison on dependencies, preventing unnecessary re-runs when object references change but values are the same.
```tsx
import { useDeepCompareEffect } from "@reactuses/core";
function FilteredList({ filters }: { filters: Record }) {
const [results, setResults] = useState([]);
// Without deepCompare, this would re-run every render because
// `filters` is a new object reference each time
useDeepCompareEffect(() => {
fetchFilteredData(filters).then(setResults);
}, [filters]);
return
{results.map(r =>
{r.name}
)}
;
}
```
---
### useRafFn — requestAnimationFrame loop
Runs a callback on every animation frame, with start/stop controls for animation loops.
```tsx
import { useRafFn } from "@reactuses/core";
import { useRef } from "react";
function ParticleCanvas() {
const canvasRef = useRef(null);
const angleRef = useRef(0);
const [stop, start] = useRafFn((timestamp) => {
const ctx = canvasRef.current?.getContext("2d");
if (!ctx) return;
ctx.clearRect(0, 0, 400, 400);
angleRef.current += 0.02;
const x = 200 + Math.cos(angleRef.current) * 100;
const y = 200 + Math.sin(angleRef.current) * 100;
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#4299e1";
ctx.fill();
});
return (
<>
>
);
}
```
---
### useTimeout — declarative setTimeout
Fires a callback once after a delay, with controls to reset or clear it.
```tsx
import { useTimeout } from "@reactuses/core";
import { useState } from "react";
function Notification({ message }: { message: string }) {
const [visible, setVisible] = useState(true);
const { clear, reset } = useTimeout(() => setVisible(false), 5000);
if (!visible) return null;
return (
{message}
);
}
```
---
### useUpdateEffect — skip first render
Like `useEffect` but skips execution on the initial mount, firing only on subsequent updates.
```tsx
import { useUpdateEffect } from "@reactuses/core";
function SearchResults({ query }: { query: string }) {
const [results, setResults] = useState([]);
// Only fires when `query` changes AFTER the first render
useUpdateEffect(() => {
analytics.track("search", { query });
search(query).then(setResults);
}, [query]);
return
{results.map(r =>
{r.name}
)}
;
}
```
---
### useMergedRefs — merge multiple refs
Combines multiple refs (callback refs and ref objects) into a single ref to attach to one element.
```tsx
import { useMergedRefs } from "@reactuses/core";
import { forwardRef, useRef } from "react";
const FancyInput = forwardRef>(
function FancyInput(props, forwardedRef) {
const localRef = useRef(null);
const mergedRef = useMergedRefs(localRef, forwardedRef);
useEffect(() => {
// Access via localRef without needing forwardedRef
localRef.current?.focus();
}, []);
return ;
}
);
```
---
### useCssVar — reactive CSS custom properties
Reads and writes a CSS custom property on a target element (defaults to `:root`).
```tsx
import { useCssVar } from "@reactuses/core";
function ThemeEditor() {
const [primaryColor, setPrimaryColor] = useCssVar("--color-primary", "#3182ce");
const [spacing, setSpacing] = useCssVar("--spacing-base", "8px");
return (
);
}
```
---
### useCountDown — countdown timer
Counts down from a target date/timestamp, returning the remaining time broken into days, hours, minutes, and seconds.
```tsx
import { useCountDown } from "@reactuses/core";
function SaleTimer() {
const saleEnd = new Date("2025-12-31T23:59:59").getTime();
const [timeLeft, formattedParts] = useCountDown(saleEnd);
if (timeLeft <= 0) return
);
}
```
---
## MCP Integration
### @reactuses/mcp — AI-powered hook discovery
The `@reactuses/mcp` package exposes three MCP tools (`get-hook-details`, `list-hooks`, `search-hooks`) so that AI assistants can look up hooks, their signatures, and documentation at generation time.
```json
// Add to your MCP client configuration (e.g., Claude Desktop config.json)
{
"mcpServers": {
"@reactuses/mcp": {
"command": "npx",
"args": ["-y", "@reactuses/mcp@latest"],
"type": "stdio"
}
}
}
```
```typescript
// MCP tools exposed by the server:
// 1. list-hooks — list all hooks or filter by category
// Input: { category?: "browser" | "state" | "element" | "effect" }
// Returns: array of { name, description, category }
// 2. get-hook-details — full signature + description for one hook
// Input: { name: "useLocalStorage" }
// Returns: { name, description, parameters, returns, example }
// 3. search-hooks — fuzzy-search hooks by keyword
// Input: { query: "clipboard", category?: "browser" }
// Returns: array of matching hooks with descriptions
```
---
## Summary
ReactUse (`@reactuses/core`) addresses the full spectrum of day-to-day React development needs through a unified, tree-shakable hooks library. State management is covered by hooks like `useLocalStorage`, `useMap`, `useBoolean`, `useCounter`, `useDebounce`, and `useThrottle`. Browser integration spans clipboard, cookies, dark mode, fullscreen, geolocation, idle detection, network status, media queries, permissions, and cross-tab messaging via `useBroadcastChannel`. DOM interactions are handled by `useDraggable`, `useHover`, `useClickOutside`, `useIntersectionObserver`, `useResizeObserver`, `useMutationObserver`, and many more. Effect utilities like `useAsyncEffect`, `useDeepCompareEffect`, `useRafFn`, and `useInterval` round out the collection.
The library integrates cleanly into any React 19 project — including SSR frameworks such as Next.js and Remix — by providing safe default values for server rendering and stable internal references that prevent infinite re-render loops. Hooks accept `BasicTarget` values (refs, raw elements, or lazy accessor functions), making them composable inside component trees and custom hooks alike. For teams using AI coding assistants, the companion `@reactuses/mcp` package exposes all hook metadata through the Model Context Protocol, enabling context-aware code generation directly from the hook documentation.