All skills

Practical playbook for React teams to choose and apply reactuse hooks across state, async flows, browser APIs, and UI interactions. Use it when replacing custom hook logic with production-ready patterns that stay compatible with SSR and Next.js.

Use this Skill: https://skilld.dev/gh/siberiacancode/agent-skills/reactuse

This session only. Nothing lands on disk.

AGENTS.md

≈66k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Reactuse

Version 1.0.16 Siberiacancode
September 2026

Note:
This document is mainly for agents and LLMs to follow when maintaining,
generating, or refactoring React and Next.js codebases. Humans
may also find it useful, but guidance here is optimized for automation
and consistency by AI-assisted workflows.


Abstract

Reactuse hook and helper playbook for React and Next.js projects, designed for AI agents and LLMs. Contains concise rules for choosing production-ready hooks, browser APIs, state helpers, async flows, sensors, lifecycle utilities, and SSR-compatible implementation patterns.

The upstream Humor category is intentionally blocked for this skill and should not be added to the supported hook set.


Table of Contents

  1. Helpers

  2. Elements

  3. Async

  4. Lifecycle

  5. Browser

  6. Utilities

  7. State

  8. User

  9. Sensors

  10. Time

  1. Debug

1. Helpers

1.1 cn

Normalizes conditional class name input into the single string React expects for className.

Usage
import { cn } from "@siberiacancode/reactuse";

const className = cn("button", active && "button-active", {
  "button-disabled": disabled,
});
Example
import { cn } from "@siberiacancode/reactuse";

export const Button = ({ active }: { active: boolean }) => {
  return (
    <button className={cn("button", { "button-active": active })}>Save</button>
  );
};

values as strings:

const className = cn("button", "button-primary");

values as conditionals:

const className = cn("button", disabled && "button-disabled");

values as arrays:

const className = cn(["button", ["button-primary"]]);

values as objects:

const className = cn({ "button-active": active });
Type Declarations
export type ClassDictionary = Record<string, any>;
export type ClassArray = readonly ClassValue[];
export type ClassValue =
  | boolean
  | number
  | string
  | ClassArray
  | ClassDictionary
  | null
  | undefined;
export declare const cn: (...values: ClassValue[]) => string;

1.2 createContext

Creates a typed context with provider and selector hook.

Usage
import { createContext } from "@siberiacancode/reactuse";

const context = createContext(0);
Example
import { createContext } from "@siberiacancode/reactuse";
import type { ReactNode } from "react";

const themeContext = createContext("light");

interface ThemeProviderProps {
  children: ReactNode;
}

export const ThemeProvider = ({ children }: ThemeProviderProps) => (
  <themeContext.Provider initialValue="light">{children}</themeContext.Provider>
);

export const CounterValue = () => {
  const theme = ThemeContext.useSelect((value) => value);
  return <span>{theme}</span>;
};

defaultValue:

const CounterContext = createContext(0);

name:

Debug display name.

const CounterContext = createContext(0, { name: "CounterContext" });

strict:

Throw outside provider.

const CounterContext = createContext(0, { strict: true });
Type Declarations
import type { JSX, ReactNode } from "react";

export interface CreateContextOptions {
  name?: string;
  strict?: boolean;
}
export interface ContextValue<Value> {
  value: Value | undefined;
  set: (value: Value) => void;
}
export interface ProviderProps<Value> {
  children?: ReactNode;
  initialValue?: Value;
}
export interface CreateContextReturn<Value> {
  instance: React.Context<ContextValue<Value>>;
  Provider: (props: ProviderProps<Value>) => JSX.Element;
  useSelect: {
    <Selected>(selector: (value: Value) => Selected): Selected;
    (): ContextValue<Value>;
  };
}
export declare const createContext: <Value>(
  defaultValue?: Value,
  options?: CreateContextOptions
) => CreateContextReturn<Value>;

1.3 createContextHook

Turns any hook into a scoped provider/consumer pair when several descendants should read the same hook result from one subtree instance.

Usage
import { createContextHook, useMediaQuery } from "@siberiacancode/reactuse";

const media = createContextHook(useMediaQuery);
Example
import { createContextHook, useMediaQuery } from "@siberiacancode/reactuse";

const media = createContextHook(useMediaQuery);

const Sidebar = () => {
  const isMobile = media.use();
  return <aside data-mobile={isMobile}>Menu</aside>;
};

export const Layout = () => (
  <media.Provider params={["(max-width: 768px)"]}>
    <Sidebar />
  </media.Provider>
);

useHook:

const media = createContextHook(useMediaQuery);

Provider.params:

<media.Provider params={["(max-width: 768px)"]}>
  <Sidebar />
</media.Provider>

use():

const isMobile = media.use();
Type Declarations
import type { ReactNode } from "react";

export declare const createContextHook: <
  Hook extends (...args: any[]) => any
>(
  useHook: Hook
) => {
  Provider: (props: {
    children: ReactNode;
    params: Parameters<Hook>;
  }) => JSX.Element;
  use: () => ReturnType<Hook> | null;
};

1.4 createEventEmitter

Creates a type-safe event emitter with a subscription hook.

Usage
import { createEventEmitter } from "@siberiacancode/reactuse";

const emitter = createEventEmitter<{
  foo: number;
}>();
Example
const emitter = createEventEmitter<{ message: string }>();

export const Listener = () => {
  const value = emitter.useSubscribe("message");
  return <div>{value ?? "none"}</div>;
};

emitter.subscribe("message", (value) => console.log(value));
emitter.push("message", "hello");
Type Declarations
export declare const createEventEmitter: <
  Events extends Record<string, any> = Record<string, any>
>() => {
  push: <Event extends keyof Events>(event: Event, data: Events[Event]) => void;
  subscribe: <Key extends keyof Events>(
    event: Key,
    listener: (data: Events[Key]) => void
  ) => () => void;
  unsubscribe: <Key extends keyof Events>(
    event: Key,
    listener: (data: Events[Key]) => void
  ) => void;
  useSubscribe: <Event extends keyof Events>(
    event: Event,
    listener?: (data: Events[Event]) => void
  ) => Events[Event] | undefined;
};

1.5 createReactiveContext

Creates a typed context selector with optimized updates.

Usage
import { createReactiveContext } from "@siberiacancode/reactuse";

const context = createReactiveContext({ count: 0 });
Example
import { createReactiveContext } from "@siberiacancode/reactuse";
import type { ReactNode } from "react";

interface UserProviderProps {
  children: ReactNode;
}

const userContext = createReactiveContext({ name: "", email: "" });

export const UserProvider = ({ children }: UserProviderProps) => (
  <userContext.Provider value={{ name: "Ada", email: "ada@example.com" }}>
    {children}
  </userContext.Provider>
);

export const UserLabel = () => {
  const name = userContext.useSelector((state) => state.name);
  return <span>{name}</span>;
};

defaultValue:

const CounterContext = createReactiveContext({ count: 0 });

name:

Debug display name.

const CounterContext = createReactiveContext(
  { count: 0 },
  { name: "CounterContext" }
);

strict:

Throw outside provider.

const CounterContext = createReactiveContext({ count: 0 }, { strict: true });
Notes
  • For complex interfaces, prefer external state management instead of context.
Type Declarations
import type { Context, Provider, RefObject } from "react";

export interface CreateReactiveContextOptions {
  name?: string;
  strict?: boolean;
}
export interface CreateReactiveContextReturn<Value> {
  instance: Context<ReactiveContextValue<Value>>;
  Provider: Provider<Value>;
  useSelector: <Selected>(selector?: (state: Value) => Selected) => Selected;
}
interface ReactiveContextValue<Value> {
  listeners: Set<(value: Value) => void>;
  value: RefObject<Value>;
}
export declare const createReactiveContext: <Value extends Record<string, any>>(
  defaultValue?: Value,
  options?: CreateReactiveContextOptions
) => CreateReactiveContextReturn<Value>;

1.6 createSharedHook

Turns a hook into a shared singleton-style hook when multiple components should subscribe to the same underlying hook result.

Usage
import { createSharedHook, useMediaQuery } from "@siberiacancode/reactuse";

const useSharedMobile = createSharedHook(useMediaQuery);
Example
import { createSharedHook, useMediaQuery } from "@siberiacancode/reactuse";

const useSharedMobile = createSharedHook(useMediaQuery);

export const Header = () => {
  const isMobile = useSharedMobile("(max-width: 768px)");
  return <header>{isMobile ? "Mobile" : "Desktop"}</header>;
};

useHook:

const useSharedOnline = createSharedHook(useOnline);

hook arguments:

const useSharedMobile = createSharedHook(useMediaQuery);
const isMobile = useSharedMobile("(max-width: 768px)");
Type Declarations
export declare const createSharedHook: <
  Hook extends (...args: any[]) => any
>(
  useHook: Hook
) => (...args: Parameters<Hook>) => ReturnType<Hook>;

1.7 createStore

Creates a external store with state, subscriptions, and a hook.

Usage
import { createStore } from "@siberiacancode/reactuse";

const store = createStore({ count: 0 });
Example
import { createStore } from "@siberiacancode/reactuse";

const counter = createStore((set) => ({
  count: 0,
  inc: () => set((state) => ({ count: state.count + 1 })),
  dec: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}));

export const Counter = () => {
  const value = counter.use((state) => state.count);
  return (
    <div>
      <button onClick={() => counter.get().dec()}>-</button>
      <span>{value}</span>
      <button onClick={() => counter.get().inc()}>+</button>
      <button onClick={() => counter.get().reset()}>Reset</button>
      <button onClick={() => counter.set({ count: 10 })}>Set 10</button>
    </div>
  );
};

Subscriptions:

const unsubscribe = counter.subscribe((state) => {
  console.log("count", state.count);
});
Type Declarations
type StoreSetAction<Value> = ((prev: Value) => Partial<Value>) | Partial<Value>;
type StoreListener<Value> = (state: Value, prevState: Value) => void;
type StoreCreator<Value> = (
  set: (action: StoreSetAction<Value>) => void,
  get: () => Value
) => Value;
export interface StoreApi<Value> {
  get: () => Value;
  getInitial: () => Value;
  set: (action: StoreSetAction<Value>) => void;
  subscribe: (listener: StoreListener<Value>) => () => void;
  use: (() => Value) &
    (<Selected>(selector: (state: Value) => Selected) => Selected) &
    (<Selected>(selector?: (state: Value) => Selected) => Selected | Value);
}
export declare const createStore: <Value>(
  createState: StoreCreator<Value> | Value
) => StoreApi<Value>;

1.8 makeDestructurable

Returns one value that can be consumed both as a named object and as a tuple, useful for hook APIs that support both styles.

Usage
import { makeDestructurable } from "@siberiacancode/reactuse";

const point = makeDestructurable({ x: 10, y: 20 }, [10, 20] as const);
Example
import { makeDestructurable } from "@siberiacancode/reactuse";

const result = makeDestructurable({ value: 1, setValue: () => {} }, [
  1,
  () => {},
] as const);

const { value } = result;
const [current] = result;

obj:

const result = makeDestructurable({ value: 1 }, [1] as const);

arr:

const result = makeDestructurable({ value: 1, setValue }, [1, setValue] as const);
Type Declarations
export declare const makeDestructurable: <
  Obj extends Record<string, unknown>,
  Arr extends readonly unknown[],
>(
  obj: Obj,
  arr: Arr,
) => Obj & Arr;

1.9 target

Wraps DOM target references in the shape Reactuse hooks understand, especially when the target is not a React ref.

Usage
import { target, useClickOutside } from "@siberiacancode/reactuse";

useClickOutside(target("#container"), () => console.log("outside"));
Example

string:

import { target, useClickOutside } from "@siberiacancode/reactuse";

useClickOutside(target("#container"), () => console.log("outside"));

Element:

useClickOutside(target(document.getElementById("container")!), () =>
  console.log("outside")
);

Document:

useClickOutside(target(document), () => console.log("document"));

Window:

useClickOutside(target(window), () => console.log("window"));

getter function:

useClickOutside(target(() => document.querySelector("#container")), () => {
  console.log("outside");
});
Type Declarations
import type { RefObject } from "react";

export type Target =
  | (() => Document | Element | Window)
  | string
  | Document
  | Element
  | Window;
interface StateRef<Value> {
  (node: Value): void;
  current: Value;
  state: Value;
}
export type HookTarget =
  | ReturnType<typeof target>
  | RefObject<Element | null | undefined>
  | StateRef<Element | null | undefined>;
export declare const target: (target: Target) => {
  value: Target;
  type: symbol;
};

2.1 useActiveElement

Tracks the currently focused element.

Usage
import { useActiveElement } from "@siberiacancode/reactuse";

const activeElement = useActiveElement<HTMLDivElement>();
// or
const activeElement = useActiveElement(ref);
Example
const activeElement = useActiveElement<HTMLDivElement>();

return (
  <>
    <div ref={activeElement.ref}>
      <input data-id="name" placeholder="Name" />
      <input data-id="email" placeholder="Email" />
    </div>
    <p>
      Active element: {activeElement.value?.getAttribute("data-id") ?? "none"}
    </p>
  </>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseActiveElementReturn<
  ActiveElement extends HTMLElement = HTMLElement
> {
  value: ActiveElement | null;
}
export interface UseActiveElement {
  (): UseActiveElementReturn<HTMLElement>;
  <Target extends Element, ActiveElement extends HTMLElement = HTMLElement>(
    target?: never
  ): {
    ref: StateRef<Target>;
  } & UseActiveElementReturn<ActiveElement>;
  <ActiveElement extends HTMLElement = HTMLElement>(
    target: HookTarget
  ): UseActiveElementReturn<ActiveElement>;
}
export declare const useActiveElement: UseActiveElement;

2.2 useAutoScroll

Automatically scrolls a container to the bottom.

Usage
import { useAutoScroll } from "@siberiacancode/reactuse";

const autoScrollRef = useAutoScroll<HTMLDivElement>();
// or
useAutoScroll(ref);
Example
const autoScrollRef = useAutoScroll<HTMLDivElement>();

return (
  <div ref={autoScrollRef}>
    <div>First message</div>
    <div>Second message</div>
  </div>
);

enabled:

Disable auto scroll.

const autoScrollRef = useAutoScroll<HTMLDivElement>({ enabled: false });

force:

Always jump to bottom.

const autoScrollRef = useAutoScroll<HTMLDivElement>({ force: true });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseAutoScrollOptions {
  enabled?: boolean;
  force?: boolean;
}
export interface UseAutoScroll {
  (target: HookTarget, options?: UseAutoScrollOptions): void;
  <Target extends HTMLElement>(options?: UseAutoScrollOptions): StateRef<Target>;
}
export declare const useAutoScroll: UseAutoScroll;

2.3 useClickOutside

Calls a callback when clicking outside the target element.

Usage
import { useClickOutside } from "@siberiacancode/reactuse";

const clickOutsideRef = useClickOutside<HTMLDivElement>(() =>
  console.log("outside")
);
// or
useClickOutside(ref, () => console.log("outside"));
Example
const [open, setOpen] = useState(true);
const clickOutsideRef = useClickOutside<HTMLDivElement>(() => setOpen(false));

if (!open) return <button onClick={() => setOpen(true)}>Open</button>;

return <div ref={clickOutsideRef}>Modal</div>;
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseClickOutside {
  (target: HookTarget, callback: (event: Event) => void): void;
  <Target extends Element>(callback: (event: Event) => void, target?: never): StateRef<Target>;
}
export declare const useClickOutside: UseClickOutside;

2.4 useContextMenu

Turns secondary-click and touch long-press gestures into menu state that can be rendered near the pointer position.

Usage
import { useContextMenu } from "@siberiacancode/reactuse";

const menu = useContextMenu<HTMLDivElement>((position) => {
  console.log(position.x, position.y);
});
// or
const menu = useContextMenu(ref, {
  onOpen: (position) => console.log(position),
});
Example
import { useContextMenu } from "@siberiacancode/reactuse";

export const CustomMenu = () => {
  const menu = useContextMenu<HTMLDivElement>({ delay: 600 });

  return (
    <div ref={menu.ref}>
      Right click me
      {menu.opened && (
        <div style={{ left: menu.position?.x, top: menu.position?.y }}>
          <button onClick={menu.close}>Close</button>
        </div>
      )}
    </div>
  );
};

callback:

const menu = useContextMenu<HTMLDivElement>((position) => {
  console.log(position.x, position.y);
});

target:

const menu = useContextMenu(target("#item-menu"), {
  onOpen: (position) => console.log(position),
});

delay:

const menu = useContextMenu<HTMLDivElement>({ delay: 700 });

enabled:

const menu = useContextMenu<HTMLDivElement>({ enabled: canOpenMenu });

onOpen:

const menu = useContextMenu<HTMLDivElement>({
  onOpen: (position) => console.log(position),
});

onClose:

const menu = useContextMenu<HTMLDivElement>({
  onClose: () => console.log("closed"),
});

onStart:

const menu = useContextMenu<HTMLDivElement>({
  onStart: (event) => console.log(event.type),
});

onEnd:

const menu = useContextMenu<HTMLDivElement>({
  onEnd: (event) => console.log(event.type),
});
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export type ContextMenuEvent = MouseEvent | TouchEvent;
export interface ContextMenuPosition {
  x: number;
  y: number;
}
export type UseContextMenuCallback = (
  position: ContextMenuPosition,
  event: ContextMenuEvent,
) => void;
export interface UseContextMenuOptions {
  delay?: number;
  enabled?: boolean;
  onOpen?: UseContextMenuCallback;
  onClose?: () => void;
  onEnd?: (event: ContextMenuEvent) => void;
  onStart?: (event: ContextMenuEvent) => void;
}
export interface UseContextMenuReturn {
  opened: boolean;
  position?: ContextMenuPosition;
  close: () => void;
  open: (position: ContextMenuPosition, event?: ContextMenuEvent) => void;
}
export interface UseContextMenu {
  (target: HookTarget, callback?: UseContextMenuCallback): UseContextMenuReturn;
  (target: HookTarget, options?: UseContextMenuOptions): UseContextMenuReturn;
  <Target extends Element>(
    callback?: UseContextMenuCallback,
  ): UseContextMenuReturn & { ref: StateRef<Target> };
  <Target extends Element>(
    options?: UseContextMenuOptions,
  ): UseContextMenuReturn & { ref: StateRef<Target> };
}
export declare const useContextMenu: UseContextMenu;

2.5 useDoubleClick

Detects double-clicks with optional single-click handler.

Usage
import { useDoubleClick } from "@siberiacancode/reactuse";

const doubleClickRef = useDoubleClick<HTMLButtonElement>(() =>
  console.log("double")
);
// or
useDoubleClick(ref, () => console.log("double"));
Example
import { useDoubleClick } from "@siberiacancode/reactuse";

export const LikeButton = () => {
  const doubleClickRef = useDoubleClick<HTMLButtonElement>(
    () => console.log("double"),
    {
      onSingleClick: () => console.log("single"),
    }
  );

  return <button ref={doubleClickRef}>Like</button>;
};

threshold:

Max time between clicks.

const doubleClickRef = useDoubleClick<HTMLButtonElement>(() => {}, {
  threshold: 400,
});

onSingleClick:

Single-click handler.

const doubleClickRef = useDoubleClick<HTMLButtonElement>(() => {}, {
  onSingleClick: () => console.log("single"),
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type DoubleClickEvents = MouseEvent | TouchEvent;
export interface UseDoubleClickOptions {
  threshold?: number;
  onSingleClick?: (event: DoubleClickEvents) => void;
}
export interface UseDoubleClick {
  (
    target: HookTarget,
    callback: (event: DoubleClickEvents) => void,
    options?: UseDoubleClickOptions
  ): void;
  <Target extends Element>(
    callback: (event: DoubleClickEvents) => void,
    options?: UseDoubleClickOptions,
    target?: never
  ): StateRef<Target>;
}
export declare const useDoubleClick: UseDoubleClick;

2.6 useDraggable

Turns pointer movement on an element into reusable drag state that can drive transforms, canvas tools, and movable panels.

Usage
import { useDraggable } from "@siberiacancode/reactuse";

const draggable = useDraggable<HTMLDivElement>();
// or
const draggable = useDraggable(ref, { axis: "x" });
Example
import { useDraggable } from "@siberiacancode/reactuse";

export const FloatingPanel = () => {
  const drag = useDraggable<HTMLDivElement>();
  const position = drag.watch();

  return (
    <div
      ref={drag.ref}
      style={{ transform: `translate(${position.x}px, ${position.y}px)` }}
    >
      Drag me
    </div>
  );
};

target:

const drag = useDraggable(target("#panel"));

axis:

const drag = useDraggable<HTMLDivElement>({ axis: "x" });

enabled:

const drag = useDraggable<HTMLDivElement>({ enabled: editable });

initialValue:

const drag = useDraggable<HTMLDivElement>({ initialValue: { x: 40, y: 20 } });

onStart:

const drag = useDraggable<HTMLDivElement>({
  onStart: ({ position }) => console.log(position),
});

onMove:

const drag = useDraggable<HTMLDivElement>({
  onMove: ({ delta }) => console.log(delta.x),
});

onEnd:

const drag = useDraggable<HTMLDivElement>({
  onEnd: ({ position }) => savePosition(position),
});
Notes
  • By default pointer movement updates snapshot and callbacks without forcing a re-render. To render live drag position in JSX, subscribe via watch(): call it once per render, for example const position = drag.watch(), then the component will re-render while dragging.
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export interface UseDraggablePosition {
  x: number;
  y: number;
}
export interface UseDraggableEvent {
  delta: UseDraggablePosition;
  event: PointerEvent;
  position: UseDraggablePosition;
}
export interface UseDraggableOptions {
  axis?: "both" | "x" | "y";
  enabled?: boolean;
  initialValue?: UseDraggablePosition;
  onEnd?: (params: UseDraggableEvent) => void;
  onMove?: (params: UseDraggableEvent) => void;
  onStart?: (params: UseDraggableEvent) => false | void;
}
export interface UseDraggableReturn {
  dragging: boolean;
  snapshot: UseDraggablePosition;
  set: (position: UseDraggablePosition) => void;
  watch: () => UseDraggablePosition;
}
export interface UseDraggable {
  (target: HookTarget, options?: UseDraggableOptions): UseDraggableReturn;
  <Target extends Element>(
    options?: UseDraggableOptions
  ): UseDraggableReturn & { ref: StateRef<Target> };
}
export declare const useDraggable: UseDraggable;

2.7 useDropZone

Creates a drag-and-drop area with file state.

Usage
import { useDropZone } from "@siberiacancode/reactuse";

const dropZone = useDropZone<HTMLDivElement>();
// or
const dropZone = useDropZone(ref, { multiple: true });
Example
import { useDropZone } from "@siberiacancode/reactuse";

export const AvatarDrop = () => {
  const dropZone = useDropZone<HTMLDivElement>({
    dataTypes: ["image/jpeg", "image/png"],
    multiple: false,
    onDrop: (files) => console.log("files", files),
  });
  const ref = dropZone.ref;

  return (
    <div ref={ref}>
      {dropZone.overed ? "Drop now" : "Drag image here"}
      <div>Files: {dropZone.files?.length ?? 0}</div>
    </div>
  );
};

dataTypes:

Allowed types.

const dropZone = useDropZone<HTMLDivElement>({ dataTypes: ["image/jpeg"] });

multiple:

Allow multiple.

const dropZone = useDropZone<HTMLDivElement>({ multiple: false });

onDrop:

Handle drop.

const dropZone = useDropZone<HTMLDivElement>({
  onDrop: (files) => console.log(files?.length ?? 0),
});

onEnter:

Drag enter.

const dropZone = useDropZone<HTMLDivElement>({
  onEnter: () => console.log("enter"),
});

onLeave:

Drag leave.

const dropZone = useDropZone<HTMLDivElement>({
  onLeave: () => console.log("leave"),
});

onOver:

Drag over.

const dropZone = useDropZone<HTMLDivElement>({
  onOver: () => console.log("over"),
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type DropZoneDataTypes = ((types: string[]) => boolean) | string[];
export interface UseDropZoneOptions {
  dataTypes?: DropZoneDataTypes;
  multiple?: boolean;
  onDrop?: (files: File[] | null, event: DragEvent) => void;
  onEnter?: (event: DragEvent) => void;
  onLeave?: (event: DragEvent) => void;
  onOver?: (event: DragEvent) => void;
}
export interface UseDropZoneReturn {
  files: File[] | null;
  overed: boolean;
}
export interface UseDropZone {
  (
    target: HookTarget,
    callback?: (files: File[] | null, event: DragEvent) => void
  ): UseDropZoneReturn;
  <Target extends Element>(
    callback?: (files: File[] | null, event: DragEvent) => void,
    target?: never
  ): UseDropZoneReturn & { ref: StateRef<Target> };
  (target: HookTarget, options?: UseDropZoneOptions): UseDropZoneReturn;
  <Target extends Element>(
    options?: UseDropZoneOptions,
    target?: never
  ): UseDropZoneReturn & { ref: StateRef<Target> };
}
export declare const useDropZone: UseDropZone;

2.8 useFileDialog

Opens a file picker and returns selected files.

Usage
import { useFileDialog } from "@siberiacancode/reactuse";

const dialog = useFileDialog();
Example
const dialog = useFileDialog({ accept: "image/*" });

return (
  <button onClick={() => dialog.open()}>
    Selected: {dialog.value?.length ?? 0}
  </button>
);

multiple:

const dialog = useFileDialog({ multiple: false });

accept:

const dialog = useFileDialog({ accept: "image/*" });

reset:

const dialog = useFileDialog({ reset: true });

capture:

const dialog = useFileDialog({ capture: "environment" });
Type Declarations
import type { ComponentProps } from "react";

export interface UseFileDialogOptions
  extends Pick<ComponentProps<"input">, "accept" | "multiple"> {
  capture?: string;
  reset?: boolean;
}
export interface UseFileDialogReturn {
  value: FileList | null;
  open: (openParams?: UseFileDialogOptions) => void;
  reset: () => void;
}
export interface UseFileDialog {
  (
    callback?: (value: FileList | null) => void,
    options?: UseFileDialogOptions
  ): UseFileDialogReturn;
  (options?: UseFileDialogOptions, callback?: never): UseFileDialogReturn;
}
export declare const useFileDialog: UseFileDialog;

2.9 useFocus

Tracks focus state and provides focus/blur controls.

Usage
import { useFocus } from "@siberiacancode/reactuse";

const focus = useFocus<HTMLInputElement>();
// or
const focus = useFocus(ref, { enabled: true });
Example
import { useFocus } from "@siberiacancode/reactuse";

export const FocusInput = () => {
  const focus = useFocus<HTMLInputElement>();

  return (
    <div>
      <input ref={focus.ref} />
      <button onClick={() => focus.focus()}>Focus</button>
      <button onClick={() => focus.blur()}>Blur</button>
    </div>
  );
};

enabled:

Enable focus tracking.

const focus = useFocus<HTMLInputElement>({ enabled: false });

initialValue:

Initial focus state.

const focus = useFocus<HTMLInputElement>({ initialValue: true });

onFocus:

Focus callback.

const focus = useFocus<HTMLInputElement>({
  onFocus: () => console.log("focus"),
});

onBlur:

Blur callback.

const focus = useFocus<HTMLInputElement>({ onBlur: () => console.log("blur") });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseFocusOptions {
  enabled?: boolean;
  initialValue?: boolean;
  onBlur?: (event: FocusEvent) => void;
  onFocus?: (event: FocusEvent) => void;
}
export interface UseFocusReturn {
  focused: boolean;
  blur: () => void;
  focus: () => void;
}
export interface UseFocus {
  (target: HookTarget, callback?: (event: FocusEvent) => void): UseFocusReturn;
  (target: HookTarget, options?: UseFocusOptions): UseFocusReturn;
  <Target extends Element>(
    callback?: (event: FocusEvent) => void,
    target?: never
  ): UseFocusReturn & { ref: StateRef<Target> };
  <Target extends Element>(
    options?: UseFocusOptions,
    target?: never
  ): UseFocusReturn & { ref: StateRef<Target> };
}
export declare const useFocus: UseFocus;

2.10 useFocusTrap

Traps focus within a given element.

Usage
import { useFocusTrap } from "@siberiacancode/reactuse";

const trap = useFocusTrap<HTMLDivElement>(true);
// or
const trap = useFocusTrap(ref, true);
Example
import { useFocusTrap } from "@siberiacancode/reactuse";

export const Modal = () => {
  const trap = useFocusTrap<HTMLDivElement>(true);

  return (
    <div ref={trap.ref}>
      <input placeholder="Search" />
      <button onClick={() => trap.disable()}>Close</button>
    </div>
  );
};

active:

Initially active.

const trap = useFocusTrap(true);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseFocusTrapReturn {
  active: boolean;
  disable: () => void;
  enable: () => void;
  toggle: () => void;
}
export interface UseFocusTrap {
  (target: HookTarget, active?: boolean): UseFocusTrapReturn;
  <Target extends HTMLElement>(
    active?: boolean,
    target?: never
  ): UseFocusTrapReturn & { ref: StateRef<Target> };
}
export declare const useFocusTrap: UseFocusTrap;

2.11 useHover

Tracks hover state for an element.

Usage
import { useHover } from "@siberiacancode/reactuse";

const hover = useHover<HTMLDivElement>();
// or
const hover = useHover(targetRef, { enabled: true });
Example
import { useHover } from "@siberiacancode/reactuse";

const hover = useHover<HTMLDivElement>();
return <div ref={hover.ref}>{hover.value ? "Hovering" : "Idle"}</div>;

enabled:

Toggle tracking.

const hover = useHover<HTMLDivElement>({ enabled: false });

onEntry:

Enter callback.

const hover = useHover<HTMLDivElement>({ onEntry: () => console.log("enter") });

onLeave:

Leave callback.

const hover = useHover<HTMLDivElement>({ onLeave: () => console.log("leave") });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseHoverOptions {
  enabled?: boolean;
  onEntry?: (event: Event) => void;
  onLeave?: (event: Event) => void;
}
export interface UseHoverReturn {
  value: boolean;
}
export interface UseHoverReturn {
  value: boolean;
}
export interface UseHover {
  (target: HookTarget, callback?: (event: Event) => void): UseHoverReturn;
  (target: HookTarget, options?: UseHoverOptions): UseHoverReturn;
  <Target extends Element>(callback?: (event: Event) => void, target?: never): {
    ref: StateRef<Target>;
  } & UseHoverReturn;
  <Target extends Element>(options?: UseHoverOptions, target?: never): {
    ref: StateRef<Target>;
  } & UseHoverReturn;
}
export declare const useHover: UseHover;

2.12 useImage

Loads an image in the browser and returns image-specific loading state.

Usage
import { useImage } from "@siberiacancode/reactuse";

const image = useImage("https://example.com/image.png");
Example

srcset:

Source of the image.

const image = useImage("/img.png", { srcset: "/img@2x.png 2x" });

sizes:

Sizes of the image.

const image = useImage("/img.png", {
  sizes: "(max-width: 600px) 100vw, 600px",
});

alt:

Alt of the image.

const image = useImage("/img.png", { alt: "Preview" });

class:

Class of the image.

const image = useImage("/img.png", { class: "rounded" });

loading:

Loading of the image.

const image = useImage("/img.png", { loading: "lazy" });

crossorigin:

Crossorigin of the image.

const image = useImage("/img.png", { crossorigin: "anonymous" });

referrerPolicy:

Referrer policy of the image.

const image = useImage("/img.png", { referrerPolicy: "no-referrer" });

onSuccess:

On success callback.

const image = useImage("/img.png", {
  onSuccess: (img) => console.log(img.src),
});

onError:

On error callback.

const image = useImage("/img.png", {
  onError: (err) => console.error(err.message),
});
Notes
Type Declarations
export interface UseImageOptions {
  alt?: string;
  class?: string;
  crossorigin?: string;
  loading?: HTMLImageElement["loading"];
  referrerPolicy?: HTMLImageElement["referrerPolicy"];
  sizes?: string;
  srcset?: string;
  onError?: (error: Error) => void;
  onSuccess?: (data: HTMLImageElement) => void;
}
export interface UseImageReturn {
  error?: Error;
  isError: boolean;
  isLoading: boolean;
  isSuccess: boolean;
  value?: HTMLImageElement;
}
export declare const useImage: (
  src: string,
  options?: UseImageOptions
) => UseImageReturn;

2.13 useLockScroll

Locks scrolling on an element or the document body.

Usage
import { useLockScroll } from "@siberiacancode/reactuse";

const lock = useLockScroll<HTMLDivElement>();
// or
const lock = useLockScroll(ref, { enabled: true });
Example
import { useLockScroll } from "@siberiacancode/reactuse";

export const Modal = () => {
  const lock = useLockScroll<HTMLDivElement>();

  return (
    <div ref={lock.ref}>
      <button onClick={() => lock.toggle()}>
        {lock.value ? "Unlock" : "Lock"} scroll
      </button>
    </div>
  );
};

enabled:

Start locked.

const lock = useLockScroll<HTMLDivElement>({ enabled: false });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseLockScrollOptions {
  enabled?: boolean;
}
export interface UseLockScrollReturn<Target extends Element> {
  ref: StateRef<Target>;
  value: boolean;
  lock: () => void;
  toggle: (value?: boolean) => void;
  unlock: () => void;
}
export interface UseLockScroll {
  (
    target: HookTarget,
    options?: UseLockScrollOptions
  ): UseLockScrollReturn<Element>;
  <Target extends Element>(
    options?: UseLockScrollOptions,
    target?: never
  ): UseLockScrollReturn<Target> & { ref: StateRef<Target> };
}
export declare const useLockScroll: UseLockScroll;

2.14 useLongPress

Detects long press interactions.

Usage
import { useLongPress } from "@siberiacancode/reactuse";

const longPress = useLongPress<HTMLButtonElement>(() =>
  console.log("long press")
);
// or
const longPress = useLongPress(ref, () => console.log("long press"));
Example
import { useLongPress } from "@siberiacancode/reactuse";

export const HoldButton = () => {
  const longPress = useLongPress<HTMLButtonElement>(() =>
    console.log("long press")
  );

  return <button ref={longPress.ref}>Hold</button>;
};

threshold:

Press duration.

const longPress = useLongPress<HTMLButtonElement>(() => {}, { threshold: 600 });

onStart:

Press start.

const longPress = useLongPress<HTMLButtonElement>(() => {}, {
  onStart: () => console.log("start"),
});

onFinish:

Press finish.

const longPress = useLongPress<HTMLButtonElement>(() => {}, {
  onFinish: () => console.log("finish"),
});

onCancel:

Press cancel.

const longPress = useLongPress<HTMLButtonElement>(() => {}, {
  onCancel: () => console.log("cancel"),
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type LongPressEvents = MouseEvent | TouchEvent;
export interface UseLongPressOptions {
  threshold?: number;
  onCancel?: (event: LongPressEvents) => void;
  onFinish?: (event: LongPressEvents) => void;
  onStart?: (event: LongPressEvents) => void;
}
export interface UseLongPressReturn {
  pressed: boolean;
}
export interface UseLongPress {
  (
    target: HookTarget,
    callback: (event: LongPressEvents) => void,
    options?: UseLongPressOptions
  ): UseLongPressReturn;
  <Target extends Element>(
    callback: (event: LongPressEvents) => void,
    options?: UseLongPressOptions,
    target?: never
  ): { ref: StateRef<Target> } & UseLongPressReturn;
}
export declare const useLongPress: UseLongPress;

2.15 usePaint

Draws on a canvas and exposes drawing controls.

Usage
import { usePaint } from "@siberiacancode/reactuse";

const paint = usePaint<HTMLCanvasElement>();
// or
const paint = usePaint(ref, { color: "red" });
Example
import { usePaint } from "@siberiacancode/reactuse";

export const Sketch = () => {
  const paint = usePaint<HTMLCanvasElement>({ color: "red", radius: 4 });
  const ref = paint.ref;

  return (
    <div>
      <canvas ref={ref} width={300} height={200} />
      <button onClick={() => paint.clear()}>Clear</button>
    </div>
  );
};

color:

Brush color.

const paint = usePaint<HTMLCanvasElement>({ color: "red" });

opacity:

Brush opacity.

const paint = usePaint<HTMLCanvasElement>({ opacity: 0.5 });

radius:

Brush size.

const paint = usePaint<HTMLCanvasElement>({ radius: 6 });

smooth:

Smoothing toggle.

const paint = usePaint<HTMLCanvasElement>({ smooth: true });

initialLines:

Restore drawings.

const paint = usePaint<HTMLCanvasElement>({ initialLines: [] });

onMouseDown:

Start drawing.

const paint = usePaint<HTMLCanvasElement>({
  onMouseDown: () => console.log("down"),
});

onMouseMove:

During drawing.

const paint = usePaint<HTMLCanvasElement>({
  onMouseMove: () => console.log("move"),
});

onMouseUp:

Stop drawing.

const paint = usePaint<HTMLCanvasElement>({
  onMouseUp: () => console.log("up"),
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface Point {
  x: number;
  y: number;
}
export interface UsePaintOptions {
  color?: string;
  initialLines?: Array<{
    points: Point[];
    color: string;
    radius: number;
    opacity: number;
  }>;
  opacity?: number;
  radius?: number;
  smooth?: boolean;
  onMouseDown?: (event: MouseEvent, paint: Paint) => void;
  onMouseMove?: (event: MouseEvent, paint: Paint) => void;
  onMouseUp?: (event: MouseEvent, paint: Paint) => void;
}
export interface UsePaintReturn {
  drawing: boolean;
  lines: Paint["lines"];
  clear: () => void;
  draw: (
    points: Point[],
    color: string,
    opacity: number,
    radius: number
  ) => void;
  undo: () => void;
}
export interface UsePaint {
  (target: HookTarget, options?: UsePaintOptions): UsePaintReturn;
  <Target extends HTMLCanvasElement>(
    options?: UsePaintOptions,
    target?: never
  ): UsePaintReturn & { ref: StateRef<Target> };
}
export declare const usePaint: UsePaint;

2.16 useScript

Loads a script and returns its status.

Usage
import { useScript } from "@siberiacancode/reactuse";

const status = useScript("https://example.com/script.js");
Example
import { useScript } from "@siberiacancode/reactuse";

const status = useScript("https://example.com/script.js");
return <div>Status: {status}</div>;

async:

const status = useScript("https://example.com/script.js", { async: false });

removeOnUnmount:

const status = useScript("https://example.com/script.js", {
  removeOnUnmount: false,
});
Type Declarations
import type { ComponentProps } from "react";

export type UseScriptStatus = "error" | "loading" | "ready" | "unknown";
export interface UseScriptOptions extends ComponentProps<"script"> {
  removeOnUnmount?: boolean;
}
export declare const useScript: (
  src: string,
  options?: UseScriptOptions
) => UseScriptStatus;

2.17 useSize

Observes element width and height.

Usage
import { useSize } from "@siberiacancode/reactuse";

const size = useSize<HTMLDivElement>();
// or
useSize(ref);
Example
import { useSize } from "@siberiacancode/reactuse";

const size = useSize<HTMLDivElement>();
return (
  <div ref={size.ref}>
    {Math.round(size.value.width)}x{Math.round(size.value.height)}
  </div>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseSizeValue {
  height: number;
  width: number;
}
export interface UseSizeReturn {
  observer?: ResizeObserver;
  value: UseSizeValue;
}
export interface UseSize {
  (target: HookTarget): UseSizeReturn;
  <Target extends Element>(target?: never): {
    ref: StateRef<Target>;
  } & UseSizeReturn;
}
export declare const useSize: UseSize;

2.18 useSticky

Detects whether a sticky element is stuck.

Usage
import { useSticky } from "@siberiacancode/reactuse";

const sticky = useSticky<HTMLDivElement>();
// or
const sticky = useSticky(ref, { axis: "vertical" });
Example
const sticky = useSticky<HTMLDivElement>();
return <div ref={sticky.ref}>{sticky.stuck ? "Stuck" : "Scrolling"}</div>;

axis:

Track axis.

const sticky = useSticky<HTMLDivElement>({ axis: "horizontal" });

root:

Scroll container.

const sticky = useSticky<HTMLDivElement>({ root: containerRef });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseStickyReturn {
  stuck: boolean;
}
export type UseStickyAxis = "horizontal" | "vertical";
export interface UseStickyOptions {
  axis?: UseStickyAxis;
  root?: HookTarget;
}
export interface UseSticky {
  (target: HookTarget, options?: UseStickyOptions): boolean;
  <Target extends Element>(options?: UseStickyOptions, target?: never): {
    ref: StateRef<Target>;
  } & UseStickyReturn;
}
export declare const useSticky: UseSticky;

2.19 useTextareaAutosize

Auto-resizes a textarea based on content.

Usage
import { useTextareaAutosize } from "@siberiacancode/reactuse";

const textarea = useTextareaAutosize<HTMLTextAreaElement>();
// or
const textarea = useTextareaAutosize(ref);
Example
import { useTextareaAutosize } from "@siberiacancode/reactuse";

export const Notes = () => {
  const textarea = useTextareaAutosize<HTMLTextAreaElement>(
    "Write your thoughts..."
  );
  const ref = textarea.ref;

  return (
    <textarea
      ref={ref}
      value={textarea.value}
      onChange={(event) => textarea.set(event.target.value)}
    />
  );
};

initialValue:

Initial text.

const textarea = useTextareaAutosize<HTMLTextAreaElement>("initial");

onResize:

Resize callback.

const textarea = useTextareaAutosize<HTMLTextAreaElement>({
  onResize: () => console.log("resize"),
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseTextareaAutosizeOptions {
  initialValue?: string;
  onResize?: () => void;
}
export interface UseTextareaAutosizeReturn {
  value: string;
  clear: () => void;
  set: (value: string) => void;
}
export interface UseTextareaAutosize {
  (
    target: HookTarget,
    options?: UseTextareaAutosizeOptions
  ): UseTextareaAutosizeReturn;
  (target: HookTarget, initialValue: string): UseTextareaAutosizeReturn;
  <Target extends HTMLTextAreaElement = HTMLTextAreaElement>(
    initialValue: string,
    target?: never
  ): UseTextareaAutosizeReturn & { ref: StateRef<Target> };
  <Target extends HTMLTextAreaElement = HTMLTextAreaElement>(
    options?: UseTextareaAutosizeOptions,
    target?: never
  ): UseTextareaAutosizeReturn & { ref: StateRef<Target> };
}
export declare const useTextareaAutosize: UseTextareaAutosize;

2.20 useTextDirection

Gets and sets the text direction of an element.

Usage
import { useTextDirection } from "@siberiacancode/reactuse";

const direction = useTextDirection<HTMLDivElement>();
// or
const direction = useTextDirection(ref, "rtl");
Example
import { useTextDirection } from "@siberiacancode/reactuse";

export const DirectionToggle = () => {
  const direction = useTextDirection<HTMLDivElement>("ltr");

  return (
    <div ref={direction.ref}>
      <button onClick={() => direction.set("rtl")}>
        Current: {direction.value}
      </button>
    </div>
  );
};

initialValue:

Initial direction.

const direction = useTextDirection<HTMLDivElement>("rtl");
direction.set("ltr");
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseTextDirectionValue = "auto" | "ltr" | "rtl";
export interface UseTextDirectionReturn {
  value: UseTextDirectionValue;
  remove: () => void;
  set: (value: UseTextDirectionValue | null) => void;
}
export interface UseTextDirection {
  (
    target: HookTarget,
    initialValue?: UseTextDirectionValue
  ): UseTextDirectionReturn;
  <Target extends Element>(
    initialValue?: UseTextDirectionValue,
    target?: never
  ): UseTextDirectionReturn & { ref: StateRef<Target> };
}
export declare const useTextDirection: UseTextDirection;

2.21 useWindowFocus

Returns the current focus state of the window.

Usage
import { useWindowFocus } from "@siberiacancode/reactuse";

const focused = useWindowFocus();
Example
import { useWindowFocus } from "@siberiacancode/reactuse";

export const FocusState = () => {
  const focused = useWindowFocus();

  return (
    <div>
      {focused ? "Focused" : "Blurred"}
      {!focused && <p>Paused while tab is inactive.</p>}
    </div>
  );
};
Type Declarations
export declare const useWindowFocus: () => boolean;

2.22 useWindowSize

Returns current window width and height.

Usage
import { useWindowSize } from "@siberiacancode/reactuse";

const size = useWindowSize();
Example
import { useWindowSize } from "@siberiacancode/reactuse";

export const Banner = () => {
  const size = useWindowSize();

  return (
    <div>
      Width: {size.width}px, Height: {size.height}px
    </div>
  );
};

includeScrollbar:

const size = useWindowSize({ includeScrollbar: false });
console.log(size.width, size.height);
Type Declarations
interface UseWindowSizeParams {
  includeScrollbar?: boolean;
}
export interface UseWindowSizeReturn {
  height: number;
  width: number;
}
export declare const useWindowSize: (
  params?: UseWindowSizeParams
) => UseWindowSizeReturn;

3. Async

3.1 useAsync

Tracks loading, error, and data state for a promise-returning callback.

Usage
import { useAsync } from "@siberiacancode/reactuse";

const userAsync = useAsync(
  () => fetch("/api/user").then((res) => res.json()),
  []
);
Example
const userAsync = useAsync<User>(
  () => fetch(`/api/me`).then((res) => res.json()),
  []
);

if (userAsync.isLoading || !userAsync.data) return <p>Loading...</p>;
if (userAsync.isError) return <p>Failed to load user.</p>;

return <div>User: {userAsync.data.name}</div>;
Type Declarations
import type { DependencyList } from "react";

export interface UseAsyncReturn<Data> {
  data?: Data;
  error?: Error;
  isError: boolean;
  isLoading: boolean;
}
export declare const useAsync: <Data>(
  callback: () => Promise<Data>,
  deps?: DependencyList
) => UseAsyncReturn<Data>;

3.2 useLockCallback

Prevents a callback from running multiple times simultaneously.

Usage
import { useLockCallback } from "@siberiacancode/reactuse";

const lockedSubmit = useLockCallback(async () => {
  await saveForm();
});
Example
import { useLockCallback } from "@siberiacancode/reactuse";

export const SaveButton = () => {
  const saveOnce = useLockCallback(async () => {
    await fetch("/api/save", { method: "POST" });
  });

  return <button onClick={saveOnce}>Save</button>;
};
Type Declarations
export declare const useLockCallback: <
  Callback extends (...args: any[]) => any
>(
  callback: Callback
) => (...args: Parameters<Callback>) => Promise<any>;

3.3 useMutation

Defines mutation logic with loading, error, and success state.

Usage
import { useMutation } from "@siberiacancode/reactuse";

const mutation = useMutation((name: string) => Promise.resolve(name));
Example

retry (boolean or number of retries):

const mutation = useMutation(saveProfile, { retry: 3 });

retryDelay (number or function):

const mutation = useMutation(saveProfile, {
  retryDelay: (attempt) => attempt * 500,
});

onSuccess (side effect on success):

const mutation = useMutation(saveProfile, {
  onSuccess: (data) => console.log("Saved", data),
});

onError (side effect on error):

const mutation = useMutation(saveProfile, {
  onError: (error) => console.error(error),
});
Type Declarations
interface UseMutationOptions<Data> {
  retry?: ((failureCount: number, error: Error) => boolean) | boolean | number;
  retryDelay?: ((retry: number, error: Error) => number) | number;
  onError?: (error: Error) => void;
  onSuccess?: (data: Data) => void;
}
interface UseMutationReturn<Body, Data> {
  data: Data | null;
  error: Error | null;
  isError: boolean;
  isLoading: boolean;
  isSuccess: boolean;
  mutate: (body?: Body, options?: UseMutationOptions<Data>) => void;
  mutateAsync: (
    body?: Body,
    options?: UseMutationOptions<Data>
  ) => Promise<Data>;
}
export declare const useMutation: <Body, Data>(
  callback: (body: Body) => Promise<Data>,
  options?: UseMutationOptions<Data>
) => UseMutationReturn<Body, Data>;

3.4 useOptimistic

Allows showing an optimistic value before the async update resolves.

Usage
import { useOptimistic } from "@siberiacancode/reactuse";

const [optimisticCount, updateOptimistic, setOptimisticCount] = useOptimistic(
  count,
  (current, delta) => current + delta
);
Example
import { useOptimistic } from "@siberiacancode/reactuse";
import { useState } from "react";

export const LikeButton = () => {
  const [likes, setLikes] = useState(0);
  const [optimisticLikes, updateOptimistic] = useOptimistic(
    likes,
    (current, delta: number) => current + delta
  );

  const onLike = () => {
    const request = fetch("/api/like", { method: "POST" }).then(() => {
      setLikes((value) => value + 1);
    });

    updateOptimistic(1, request);
  };

  return <button onClick={onLike}>Likes: {optimisticLikes}</button>;
};
Notes
  • The third tuple item is the internal setState, useful when you need to imperatively replace the optimistic state.
Type Declarations
export type UseOptimisticReturn<State> = [
  State,
  (optimisticValue: State, promise: Promise<any>) => void
];
export declare const useOptimistic: <State, OptimisticState = State>(
  externalState: State,
  update: (currentState: State, optimisticState: OptimisticState) => State
) => readonly [
  State,
  (optimisticValue: OptimisticState, promise: Promise<any>) => Promise<any>,
  React.Dispatch<React.SetStateAction<State>>
];

3.5 useQuery

Wraps an abortable async read in query state so components can express loading, refresh, retry, cancellation, and selected data without hand-rolling request bookkeeping.

Usage
import { useQuery } from "@siberiacancode/reactuse";

const query = useQuery(({ signal }) =>
  fetch("/api/user", { signal }).then((res) => res.json())
);
Example

enabled:

const query = useQuery(fetchUser, { enabled: isOpen });

keys:

const query = useQuery(fetchUser, { keys: [userId] });

placeholderData:

const query = useQuery(fetchUser, { placeholderData: { name: "Loading..." } });

refetchInterval:

Use a number to refetch on a fixed interval.

const query = useQuery(fetchStats, { refetchInterval: 5000 });

Use a function to choose the interval dynamically or return false.

const query = useQuery(fetchStats, {
  refetchInterval: () => (document.hidden ? false : 5000),
});

retry:

Use a number for a fixed retry count.

const query = useQuery(fetchUser, { retry: 3, retryDelay: 500 });

Use a function to decide whether each failed request should retry.

const query = useQuery(fetchUser, {
  retry: (failureCount, error) => failureCount < 3 && error.message !== "401",
  retryDelay: 500,
});

retryDelay:

const query = useQuery(fetchUser, { retry: 3, retryDelay: 500 });

select:

const query = useQuery(fetchUser, {
  select: (data) => data.profile,
});

onError:

const query = useQuery(fetchUser, {
  onError: (error) => toast.error(error.message),
});

onSuccess:

const query = useQuery(fetchUser, {
  onSuccess: (user) => console.log(user.id),
});
Type Declarations
import type { DependencyList } from "react";

export interface UseQueryOptions<QueryData, Data> {
  enabled?: boolean;
  keys?: DependencyList;
  placeholderData?: (() => Data) | Data;
  refetchInterval?: (() => number | false) | number | false;
  retry?: ((failureCount: number, error: Error) => boolean) | boolean | number;
  retryDelay?: number;
  onError?: (error: Error) => void;
  onSuccess?: (data: Data) => void;
  select?: (data: QueryData) => Data;
}
interface UseQueryCallbackParams {
  keys: DependencyList;
  signal: AbortSignal;
}
export interface UseQueryReturn<Data> {
  abort: AbortController["abort"];
  data?: Data;
  error?: Error;
  isError: boolean;
  isFetching: boolean;
  isLoading: boolean;
  isRefetching: boolean;
  isSuccess: boolean;
  fetch: () => Promise<void>;
  refetch: () => void;
}
export declare const useQuery: <QueryData, Data = QueryData>(
  callback: (params: UseQueryCallbackParams) => Promise<QueryData>,
  options?: UseQueryOptions<QueryData, Data>
) => UseQueryReturn<Data>;

4.1 useAsyncEffect

Runs async side effects.

Usage
import { useAsyncEffect } from "@siberiacancode/reactuse";

useAsyncEffect(async () => {
  console.log("async effect");
}, deps);
Example
useAsyncEffect(async () => {
  const response = await fetch("/api/me").then((response) => response.json());
  console.log(response.data);
}, [message.id]);

//...
Type Declarations
import type { DependencyList } from "react";

export declare const useAsyncEffect: (
  callback: () => Promise<any>,
  deps?: DependencyList
) => void;

4.2 useDidUpdate

Runs an effect only on updates (not on initial mount).

Usage
import { useDidUpdate } from "@siberiacancode/reactuse";

useDidUpdate(() => console.log("updated"), [value]);
Example
import { useDidUpdate } from "@siberiacancode/reactuse";

interface ProfileProps {
  name: string;
}

export const Profile = ({ name }: ProfileProps) => {
  useDidUpdate(() => {
    console.log("name changed");
  }, [name]);

  return <div>{name}</div>;
};
Type Declarations
import type { DependencyList, EffectCallback } from "react";

export declare const useDidUpdate: (
  effect: EffectCallback,
  deps?: DependencyList
) => void;

4.3 useIsFirstRender

Returns true only on the first render.

Usage
import { useIsFirstRender } from "@siberiacancode/reactuse";

const isFirst = useIsFirstRender();
Example
import { useIsFirstRender } from "@siberiacancode/reactuse";

export const Banner = () => {
  const isFirst = useIsFirstRender();
  return <div>{isFirst ? "Welcome!" : "Welcome back"}</div>;
};
Type Declarations
export declare const useIsFirstRender: () => boolean;

4.4 useIsomorphicLayoutEffect

Uses useLayoutEffect on the client and useEffect on the server.

Usage
import { useIsomorphicLayoutEffect } from "@siberiacancode/reactuse";

useIsomorphicLayoutEffect(() => {}, []);
Example
useIsomorphicLayoutEffect(() => {}, []);
Type Declarations
import type { useEffect } from "react";

export declare const useIsomorphicLayoutEffect: typeof useEffect;

4.5 useMount

Runs a callback once when the component mounts.

Usage
import { useMount } from "@siberiacancode/reactuse";

useMount(() => console.log("mounted"));
Example
import { useMount } from "@siberiacancode/reactuse";

export const Tracker = () => {
  useMount(() => {
    console.log("track mount");
  });

  return <div>Mounted</div>;
};
Type Declarations
import type { EffectCallback } from "react";

export declare const useMount: (effect: EffectCallback) => void;

4.6 useShallowEffect

Runs an effect only when dependencies change shallowly or deeply.

Usage
import { useShallowEffect } from "@siberiacancode/reactuse";

useShallowEffect(() => console.log("effect"), [user]);
Example
import { useShallowEffect } from "@siberiacancode/reactuse";

interface UserCardProps {
  user: {
    id: string;
    name: string;
  };
}

export const UserCard = ({ user }: UserCardProps) => {
  useShallowEffect(() => console.log("effect"), [user]);

  return <div>{user.name}</div>;
};
Notes
  • Uses a deep comparison helper to decide if dependencies changed.
Type Declarations
import type { DependencyList, EffectCallback } from "react";

export declare const deepEqual: (a: any, b: any) => boolean;
export declare const useShallowEffect: (
  effect: EffectCallback,
  deps?: DependencyList
) => void;

4.7 useUnmount

Runs a callback when the component unmounts.

Usage
import { useUnmount } from "@siberiacancode/reactuse";

useUnmount(() => console.log("unmounted"));
Example
import { useUnmount } from "@siberiacancode/reactuse";

export const Cleanup = () => {
  useUnmount(() => {
    console.log("cleanup");
  });

  return <div>Unmount me</div>;
};
Type Declarations
export declare const useUnmount: (callback: () => void) => void;

5. Browser

5.1 useAudio

Manages audio playback (play/pause/stop), volume, rate, and sprite segments.

Usage
import { useAudio } from "@siberiacancode/reactuse";

const audio = useAudio("/sounds/pop.mp3");
import { useAudio } from "@siberiacancode/reactuse";

const audio = useAudio("/sounds/sprite.mp3", {
  sprite: {
    click: [0, 0.25],
    success: [0.6, 1.1],
  },
});
Example
const audio = useAudio("/sounds/track.mp3");

return (
  <div>
    <button onClick={() => audio.play()}>Play</button>
    <button onClick={audio.pause}>Pause</button>
    <button onClick={audio.stop}>Stop</button>
  </div>
);

immediately:

Try to autoplay on mount.

const audio = useAudio("/sounds/alert.mp3", { immediately: true });

interrupt:

Stop current playback before starting.

const audio = useAudio("/sounds/click.mp3", { interrupt: true });

<button onClick={() => audio.play()}>Play</button>;

playbackRate:

Speed from 0.5 to 2.

const audio = useAudio("/sounds/typing.mp3", { playbackRate: 1.5 });

sprite:

Play named segment.

const audio = useAudio("/sounds/ui-sprite.mp3", {
  sprite: {
    open: [0, 0.2],
    close: [0.3, 0.5],
  },
});

<button onClick={() => audio.play("open")}>Open</button>;

volume:

Level from 0 to 1.

const audio = useAudio("/sounds/ambient.mp3", { volume: 0.3 });
Notes
Type Declarations
import type {
  SpriteMap,
  UseAudioOptions,
  UseAudioReturn,
} from "@siberiacancode/reactuse";

export interface SpriteMap {
  [key: string]: [number, number];
}
export interface UseAudioOptions {
  immediately?: boolean;
  interrupt?: boolean;
  playbackRate?: number;
  sprite?: SpriteMap;
  volume?: number;
}
export interface UseAudioReturn {
  playbackRate: number;
  playing: boolean;
  volume: number;
  changePlaybackRate: (value: number) => void;
  pause: () => void;
  play: (sprite?: string) => Promise<void>;
  setVolume: (value: number) => void;
  stop: () => void;
}
export declare const useAudio: (
  src: string,
  options?: UseAudioOptions
) => UseAudioReturn;

5.2 useBattery

Returns battery status and support state.

Usage
import { useBattery } from "@siberiacancode/reactuse";

const battery = useBattery();
Example
import { useBattery } from "@siberiacancode/reactuse";

export const BatteryStatus = () => {
  const battery = useBattery();
  if (!battery.supported) return <div>Not supported</div>;

  return (
    <div>
      Level: {Math.round(battery.value.level * 100)}%{" "}
      {battery.value.charging ? "(charging)" : ""}
    </div>
  );
};
Use cases

Our applications normally are not empathetic to battery level, we can make a few adjustments to our applications that will be more friendly to low battery users.

  • Trigger a special "dark-mode" battery saver theme settings.
  • Stop auto playing videos in news feeds.
  • Disable some background workers that are not critical.
  • Limit network calls and reduce CPU/Memory consumption.
Notes
Type Declarations
export interface UseBatteryValue {
  charging: boolean;
  chargingTime: number;
  dischargingTime: number;
  level: number;
  loading: boolean;
}
export interface UseBatteryReturn {
  supported: boolean;
  value: UseBatteryValue;
}
export declare const useBattery: () => UseBatteryReturn;

5.3 useBluetooth

Requests and connects to Bluetooth devices.

Usage
import { useBluetooth } from "@siberiacancode/reactuse";

const bluetooth = useBluetooth();
Example
import { useBluetooth } from "@siberiacancode/reactuse";

export const BluetoothStatus = () => {
  const bluetooth = useBluetooth({ acceptAllDevices: true });

  if (!bluetooth.supported) return <p>Not supported</p>;

  return (
    <div>
      <button onClick={() => bluetooth.requestDevice()}>Request device</button>
      <p>Connected: {String(bluetooth.connected)}</p>
    </div>
  );
};

acceptAllDevices:

Show all nearby devices in the chooser.

const bluetooth = useBluetooth({ acceptAllDevices: true });

filters:

Filter devices by name/service.

const bluetooth = useBluetooth({
  filters: [{ namePrefix: "Device" }],
});

optionalServices:

Request additional GATT services.

const bluetooth = useBluetooth({
  optionalServices: ["battery_service"],
});

Battery level example:

This sample illustrates the use of the Web Bluetooth API to read battery level and be notified of changes from a nearby Bluetooth Device advertising Battery information with Bluetooth Low Energy.

Here, we use the characteristicvaluechanged event listener to handle reading battery level characteristic value. This event listener will optionally handle upcoming notifications as well.

import { useBluetooth } from "@siberiacancode/reactuse";
import { useEffect, useRef, useState } from "react";

export const BatteryMonitor = () => {
  const bluetooth = useBluetooth({
    acceptAllDevices: true,
    optionalServices: ["battery_service"],
  });

  const [battery, setBattery] = useState<number | undefined>();
  const characteristicRef = useRef<BluetoothRemoteGATTCharacteristic>();

  useEffect(() => {
    const server = bluetooth.server;
    if (!server) return;

    const onChange = (event: Event) => {
      const characteristic = event.target as BluetoothRemoteGATTCharacteristic;
      const value = characteristic.value?.getUint8(0);
      if (value != null) setBattery(value);
    };

    const connect = async () => {
      const service = await server.getPrimaryService("battery_service");
      const characteristic = await service.getCharacteristic("battery_level");

      characteristicRef.current = characteristic;

      characteristic.addEventListener("characteristicvaluechanged", onChange);
      await characteristic.startNotifications();

      const initial = await characteristic.readValue();
      setBattery(initial.getUint8(0));
    };

    connect();

    return () => {
      const characteristic = characteristicRef.current;
      if (!characteristic) return;

      characteristic.removeEventListener(
        "characteristicvaluechanged",
        onChange
      );
      characteristic.stopNotifications();
      characteristicRef.current = null;
    };
  }, [bluetooth.server]);

  return (
    <div>
      <button onClick={() => bluetooth.requestDevice()}>Request device</button>

      <p>Connected: {String(bluetooth.connected)}</p>
      <p>Battery: {battery != null ? `${battery}%` : "—"}</p>
    </div>
  );
};
Notes
Type Declarations
export interface UseBluetoothReturn {
  connected: boolean;
  device?: BluetoothDevice;
  server?: BluetoothRemoteGATTServer;
  supported: boolean;
  requestDevice: () => Promise<void>;
}
export interface UseBluetoothOptions {
  acceptAllDevices?: boolean;
  filters?: BluetoothLEScanFilter[];
  optionalServices?: BluetoothServiceUUID[];
}
export declare const useBluetooth: (
  options?: UseBluetoothOptions
) => UseBluetoothReturn;

5.4 useBreakpoints

Manages responsive breakpoints and helper predicates.

Usage
import { useBreakpoints } from "@siberiacancode/reactuse";

const breakpoints = useBreakpoints({ mobile: 0, tablet: 640, desktop: 1024 });
Example
const breakpoints = useBreakpoints({ sm: 640, md: 768, lg: 1024 });

const active = breakpoints.active();

return (
  <div>
    Active: {active}
    <div>Is large: {String(breakpoints.greaterOrEqual("lg"))}</div>
  </div>
);

breakpoints:

Breakpoint map with pixel values.

const breakpoints = useBreakpoints({ sm: 640, md: 768, lg: 1024 });

strategy:

The strategy option controls how the shortcut properties behave:

  • min-width (default, mobile-first): breakpoints.lg is true when viewport is >= lg
  • max-width (desktop-first): breakpoints.lg is true when viewport is < xl
const breakpoints = useBreakpoints({ sm: 640, md: 768 }, "desktop-first");

between:

Check if width is between two breakpoints.

const breakpoints = useBreakpoints({ sm: 640, md: 768, lg: 1024 });
const isTablet = breakpoints.between("sm", "lg");
Presets
  • Material UI: BREAKPOINTS_MATERIAL_UI
  • Mantine: BREAKPOINTS_MANTINE
  • Tailwind: BREAKPOINTS_TAILWIND
  • Bootstrap v5: BREAKPOINTS_BOOTSTRAP_V5
  • Ant Design: BREAKPOINTS_ANT_DESIGN
  • Quasar v2: BREAKPOINTS_QUASAR_V2
  • Sematic: BREAKPOINTS_SEMANTIC
  • Master CSS: BREAKPOINTS_MASTER_CSS
  • Prime Flex: BREAKPOINTS_PRIME_FLEX
import { BREAKPOINTS_TAILWIND } from "@siberiacancode/reactuse";
Notes
  • Use only when CSS cannot solve the layout.
Type Declarations
export type Breakpoints<Breakpoint extends string = string> = Record<
  Breakpoint,
  number
>;
export type UseBreakpointsStrategy = "desktop-first" | "mobile-first";
export type UseBreakpointsReturn<Breakpoint extends string = string> = {
  greater: (breakpoint: Breakpoint) => boolean;
  greaterOrEqual: (breakpoint: Breakpoint) => boolean;
  smaller: (breakpoint: Breakpoint) => boolean;
  smallerOrEqual: (breakpoint: Breakpoint) => boolean;
  between: (a: Breakpoint, b: Breakpoint) => boolean;
  current: () => Breakpoint[];
  active: () => Breakpoint;
} & Record<Breakpoint, boolean>;
export declare const useBreakpoints: <Breakpoint extends string>(
  breakpoints: Breakpoints<Breakpoint>,
  strategy?: UseBreakpointsStrategy
) => UseBreakpointsReturn<Breakpoint>;

5.5 useBroadcastChannel

Enables cross-tab/window messaging.

Usage
import { useBroadcastChannel } from "@siberiacancode/reactuse";

const channel = useBroadcastChannel("channel");
Example
const channel = useBroadcastChannel<string>("sync", (message) => {
  console.log(message);
});

return (
  <button onClick={() => channel.post("ping")}>
    Last: {channel.data ?? "none"}
  </button>
);
Notes
Type Declarations
export interface UseBroadcastChannelReturn<Data = unknown> {
  channel?: BroadcastChannel;
  closed: boolean;
  data?: Data;
  error?: Event;
  supported: boolean;
  close: () => void;
  post: (data: Data) => void;
}
export declare const useBroadcastChannel: <Data = unknown>(
  name: string,
  callback?: (data: Data) => void
) => UseBroadcastChannelReturn<Data>;

5.6 useBrowserLocation

Returns reactive browser location state with navigation controls.

Usage
import { useBrowserLocation } from "@siberiacancode/reactuse";

const location = useBrowserLocation();
Example
import { useBrowserLocation } from "@siberiacancode/reactuse";

export const BrowserLocationControls = () => {
  const location = useBrowserLocation();

  return (
    <div>
      <p>Path: {location.value.pathname}</p>
      <button onClick={() => location.push("/dashboard?tab=overview")}>
        Push
      </button>
      <button onClick={() => location.replace("/dashboard?tab=settings")}>
        Replace
      </button>
      <button onClick={() => location.back()}>Back</button>
      <button onClick={() => location.forward()}>Forward</button>
    </div>
  );
};
Notes
Type Declarations
export interface BrowserLocationState {
  hash?: string;
  host?: string;
  hostname?: string;
  href?: string;
  length?: number;
  origin?: string;
  pathname?: string;
  port?: string;
  protocol?: string;
  search?: string;
  searchParams: URLSearchParams;
  state?: unknown;
}
export interface UseBrowserLocationReturn {
  value: BrowserLocationState;
  back: () => void;
  forward: () => void;
  go: (delta: number) => void;
  push: (url: string | URL, state?: unknown, title?: string) => void;
  replace: (url: string | URL, state?: unknown, title?: string) => void;
}
export declare const useBrowserLocation: () => UseBrowserLocationReturn;

5.7 useClipboard

Reads and copies text from the clipboard.

Usage
import { useClipboard } from "@siberiacancode/reactuse";

const clipboard = useClipboard();
Example

Copy button:

const clipboard = useClipboard();

return (
  <button onClick={() => clipboard.copy("team@example.com")}>
    {clipboard.value ?? "Copy email"}
  </button>
);

enabled (track copy/cut events):

const clipboard = useClipboard({ enabled: true });
Notes
Type Declarations
export interface UseCopyToClipboardReturn {
  value: string | null;
  copy: (value: string) => Promise<void>;
}
export interface UseCopyToClipboardParams {
  enabled: boolean;
}
export declare const useClipboard: (
  params?: UseCopyToClipboardParams
) => UseCopyToClipboardReturn;

5.8 useCopy

Copies text and resets status after a delay.

Usage
import { useCopy } from "@siberiacancode/reactuse";

const copyState = useCopy();
Example
const linkCopy = useCopy(1500);

return (
  <button onClick={() => linkCopy.copy("https://reactuse.org")}>
    {linkCopy.copied ? "Copied!" : "Copy link"}
  </button>
);

delay (reset timeout):

const copyState = useCopy(2000);
Notes
Type Declarations
export interface UseCopyReturn {
  copied: boolean;
  value?: string;
  copy: (value: string) => Promise<void>;
}
export declare const useCopy: (delay?: number) => UseCopyReturn;

5.9 useCssVar

Reads and writes a CSS custom property.

Usage
import { useCssVar } from "@siberiacancode/reactuse";

const cssVar = useCssVar<HTMLDivElement>("--color", "red");
// or
const cssVar = useCssVar(ref, "--color", "red");
Example
const cssVar = useCssVar<HTMLDivElement>("--bg", "tomato");

return (
  <div ref={cssVar.ref} style={{ background: cssVar.value }}>
    <button onClick={() => cssVar.set("steelblue")}>Change</button>
  </div>
);

Targeted element:

const cssVar = useCssVar<HTMLDivElement>("--panel-bg", "#111");

return (
  <section ref={cssVar.ref} style={{ background: cssVar.value }}>
    <button onClick={() => cssVar.set("#333")}>Darken</button>
    <button onClick={() => cssVar.remove()}>Reset</button>
  </section>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseCssVarReturn {
  value: string;
  remove: () => void;
  set: (value: string) => void;
}
export interface UseCssVar {
  <Target extends HTMLElement>(
    key: string,
    initialValue?: string
  ): UseCssVarReturn & { ref: StateRef<Target> };
  (target: HookTarget, key: string, initialValue?: string): UseCssVarReturn;
}
export declare const useCssVar: UseCssVar;

5.10 useDeviceList

Keeps the available media input and output devices grouped for UI pickers after permissions are requested.

Usage
import { useDeviceList } from "@siberiacancode/reactuse";

const devices = useDeviceList();
Example
import { useDeviceList } from "@siberiacancode/reactuse";

export const CameraPicker = () => {
  const devices = useDeviceList({ immediately: false });

  return (
    <div>
      <button onClick={() => devices.trigger()}>Load devices</button>
      <select>
        {devices.videoInputs.map((device) => (
          <option key={device.deviceId} value={device.deviceId}>
            {device.label || "Camera"}
          </option>
        ))}
      </select>
    </div>
  );
};

constraints:

const devices = useDeviceList({ constraints: { video: true, audio: true } });

callback:

const devices = useDeviceList((items) => console.log(items.length));

immediately:

const devices = useDeviceList({ immediately: false });

onUpdate:

const devices = useDeviceList({
  onUpdate: (items) => console.log(items.length),
});
Notes
Type Declarations
export type UseDeviceListCallback = (devices: MediaDeviceInfo[]) => void;
export interface UseDeviceListOptions {
  constraints?: MediaStreamConstraints;
  immediately?: boolean;
  onUpdate?: UseDeviceListCallback;
}
export interface UseDeviceListReturn {
  audioInputs: MediaDeviceInfo[];
  audioOutputs: MediaDeviceInfo[];
  devices: MediaDeviceInfo[];
  supported: boolean;
  videoInputs: MediaDeviceInfo[];
  trigger: () => Promise<MediaDeviceInfo[] | undefined>;
  update: () => Promise<MediaDeviceInfo[] | undefined>;
}
export interface UseDeviceList {
  (callback?: UseDeviceListCallback): UseDeviceListReturn;
  (options?: UseDeviceListOptions): UseDeviceListReturn;
}
export declare const useDeviceList: UseDeviceList;

5.11 useDisplayMedia

Connects a video element to a screen-capture stream and keeps capture state under React control.

Usage
import { useDisplayMedia } from "@siberiacancode/reactuse";

const displayMedia = useDisplayMedia<HTMLVideoElement>();
// or
const displayMedia = useDisplayMedia(ref, {
  constraints: { video: true, audio: false },
});
Example
import { useDisplayMedia } from "@siberiacancode/reactuse";

export const ScreenShare = () => {
  const displayMedia = useDisplayMedia<HTMLVideoElement>({
    constraints: { video: true, audio: false },
  });

  return (
    <div>
      <button onClick={() => displayMedia.start()}>Start</button>
      <button onClick={displayMedia.stop}>Stop</button>
      <video ref={displayMedia.ref} autoPlay muted />
      {displayMedia.active && <span>Sharing</span>}
    </div>
  );
};

start(constraints):

await displayMedia.start({ video: { displaySurface: "browser" } });

constraints:

const displayMedia = useDisplayMedia<HTMLVideoElement>({
  constraints: { video: true, audio: false },
});

immediately:

const displayMedia = useDisplayMedia(videoRef, { immediately: true });

onStart:

const displayMedia = useDisplayMedia<HTMLVideoElement>({
  onStart: (stream) => console.log(stream),
});

onStop:

const displayMedia = useDisplayMedia<HTMLVideoElement>({
  onStop: () => console.log("stopped"),
});
Notes
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export interface UseDisplayMediaConstraints {
  audio?: boolean | MediaTrackConstraints;
  video?: boolean | MediaTrackConstraints;
}
export interface UseDisplayMediaReturn {
  active: boolean;
  stream: MediaStream | null;
  supported: boolean;
  start: (constraints?: UseDisplayMediaConstraints) => Promise<MediaStream | undefined>;
  stop: () => void;
}
export interface UseDisplayMediaOptions {
  constraints?: UseDisplayMediaConstraints;
  immediately?: boolean;
  onStart?: (stream: MediaStream) => void;
  onStop?: (stream?: MediaStream) => void;
}
export interface UseDisplayMedia {
  (target: HookTarget, options?: UseDisplayMediaOptions): UseDisplayMediaReturn;
  <Target extends HTMLVideoElement>(
    options?: UseDisplayMediaOptions
  ): UseDisplayMediaReturn & { ref: StateRef<Target> };
}
export declare const useDisplayMedia: UseDisplayMedia;

5.12 useDocumentEvent

Attaches an event listener to the document.

Usage
import { useDocumentEvent } from "@siberiacancode/reactuse";

useDocumentEvent("click", () => console.log("clicked"));
Example
useDocumentEvent("keydown", (event) => {
  if (event.key === "Escape") onClose();
});

enabled:

useDocumentEvent("click", () => {}, { enabled: false });
Type Declarations
import type { UseEventListenerOptions } from "@siberiacancode/reactuse";

export declare const useDocumentEvent: <Event extends keyof DocumentEventMap>(
  event: Event,
  listener: (this: Document, event: DocumentEventMap[Event]) => any,
  options?: UseEventListenerOptions
) => void;

5.13 useDocumentTitle

Reads and updates the document title.

Usage
import { useDocumentTitle } from "@siberiacancode/reactuse";

const title = useDocumentTitle("My App");
Example
import { useDocumentTitle } from "@siberiacancode/reactuse";

export const TitleEditor = () => {
  const title = useDocumentTitle("Dashboard");

  return (
    <input
      value={title.value}
      onChange={(event) => title.set(event.target.value)}
    />
  );
};

initialValue:

const title = useDocumentTitle("Dashboard");

restore:

const title = useDocumentTitle("Profile", { restore: true });
Notes
Type Declarations
export interface UseDocumentTitleOptions {
  restore?: boolean;
}
export interface UseDocumentTitleReturn {
  value: string;
  set: (title: string) => void;
}
export declare function useDocumentTitle(
  initialValue?: string,
  options?: UseDocumentTitleOptions
): UseDocumentTitleReturn;

5.14 useDocumentVisibility

Returns the document visibility state.

Usage
import { useDocumentVisibility } from "@siberiacancode/reactuse";

const documentVisibility = useDocumentVisibility();
Example
const documentVisibility = useDocumentVisibility();
return <div>{documentVisibility === "hidden" ? "Hidden" : "Visible"}</div>;

callback:

const documentVisibility = useDocumentVisibility((state) => {
  if (state === "hidden") console.log("user left tab");
});
Type Declarations
export declare const useDocumentVisibility: (
  callback?: (state: DocumentVisibilityState) => void
) => DocumentVisibilityState;

5.15 useEventListener

Attaches an event listener to a target.

Usage
import { useEventListener } from "@siberiacancode/reactuse";

useEventListener(window, "click", () => console.log("click"));
// or
const eventListenerRef = useEventListener<HTMLButtonElement>("click", () =>
  console.log("click")
);
Example
import { useEventListener } from "@siberiacancode/reactuse";

export const ClickTracker = () => {
  const eventListenerRef = useEventListener<HTMLButtonElement>("click", () => {
    console.log("clicked");
  });

  return <button ref={eventListenerRef}>Track clicks</button>;
};

enabled:

Toggle listener.

useEventListener(window, "scroll", () => {}, { enabled: false });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseEventListenerOptions = {
  enabled?: boolean;
} & AddEventListenerOptions;
export type UseEventListenerReturn<Target extends Element> = StateRef<Target>;
export interface UseEventListener {
  <Event extends keyof WindowEventMap = keyof WindowEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Window, event: WindowEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;
  <Event extends keyof DocumentEventMap = keyof DocumentEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Document, event: DocumentEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;
  <Event extends keyof HTMLElementEventMap = keyof HTMLElementEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Element, event: HTMLElementEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;
  <
    Target extends Element,
    Event extends keyof HTMLElementEventMap = keyof HTMLElementEventMap
  >(
    event: Event,
    listener: (this: Target, event: HTMLElementEventMap[Event]) => void,
    options?: UseEventListenerOptions,
    target?: never
  ): UseEventListenerReturn<Target>;
  <
    Target extends Element,
    Event extends keyof MediaQueryListEventMap = keyof MediaQueryListEventMap
  >(
    event: Event,
    listener: (this: Target, event: MediaQueryListEventMap[Event]) => void,
    options?: UseEventListenerOptions,
    target?: never
  ): UseEventListenerReturn<Target>;
}
export declare const useEventListener: UseEventListener;

5.16 useEventSource

Provides a reactive wrapper around EventSource.

Usage
import { useEventSource } from "@siberiacancode/reactuse";

const stream = useEventSource("/sse", ["message"]);
Example
import { useEventSource } from "@siberiacancode/reactuse";

export const Feed = () => {
  const stream = useEventSource("/sse", ["message"]);

  return <div>Last: {stream.data ?? "waiting"}</div>;
};

immediately (auto-open):

const stream = useEventSource("/sse", [], { immediately: true });

placeholderData:

const stream = useEventSource("/sse", [], {
  placeholderData: { status: "idle" },
});

retry:

const stream = useEventSource("/sse", [], { retry: 3 });

retryDelay:

const stream = useEventSource("/sse", [], {
  retryDelay: (attempt) => attempt * 500,
});

onOpen:

const stream = useEventSource("/sse", [], {
  onOpen: () => console.log("open"),
});

onMessage:

const stream = useEventSource("/sse", [], {
  onMessage: (event) => console.log(event.data),
});

onError:

const stream = useEventSource("/sse", [], {
  onError: (event) => console.error(event),
});

select:

const stream = useEventSource<string, { value: string }>("/sse", [], {
  select: (data) => JSON.parse(data),
});
Notes
Type Declarations
export interface UseEventSourceOptions<QueryData, Data>
  extends EventSourceInit {
  immediately?: boolean;
  placeholderData?: (() => Data) | Data;
  retry?: boolean | number;
  retryDelay?: ((retry: number, event: Event) => number) | number;
  onError?: (error: Event) => void;
  onMessage?: (event: Event & { data?: Data }) => void;
  onOpen?: () => void;
  select?: (data: QueryData) => Data;
}
interface UseEventSourceReturn<Data = any> {
  data?: Data;
  error?: Event;
  instance?: EventSource;
  isConnecting: boolean;
  isError: boolean;
  opened: boolean;
  close: () => void;
  open: () => void;
}
export declare const useEventSource: <QueryData = any, Data = QueryData>(
  url: string | URL,
  events?: string[],
  options?: UseEventSourceOptions<QueryData, Data>
) => UseEventSourceReturn<Data>;

5.17 useEyeDropper

Provides access to the EyeDropper API.

Usage
import { useEyeDropper } from "@siberiacancode/reactuse";

const eyeDropper = useEyeDropper();
Example
const eye = useEyeDropper("#ffffff");

return <button onClick={() => eye.open()}>{eye.value ?? "Pick color"}</button>;

initialValue:

const eye = useEyeDropper("#ffffff");
Notes
Type Declarations
export interface ColorSelectionOptions {
  signal?: AbortSignal;
}
export interface ColorSelectionResult {
  sRGBHex: string;
}
export interface UseEyeDropperReturn {
  supported: boolean;
  value?: string;
  open: (
    colorSelectionOptions?: ColorSelectionOptions
  ) => Promise<ColorSelectionResult>;
}
export declare const useEyeDropper: (
  initialValue?: string
) => UseEyeDropperReturn;

5.18 useFavicon

Reads and updates the current favicon.

Usage
import { useFavicon } from "@siberiacancode/reactuse";

const favicon = useFavicon();
Example
const favicon = useFavicon("/light.ico");

return (
  <button onClick={() => favicon.set("/dark.ico")}>
    Current: {favicon.href}
  </button>
);

initialFavicon:

const favicon = useFavicon("https://example.com/favicon.ico");
Type Declarations
import type { Dispatch, SetStateAction } from "react";

export type UseFaviconReturn = [string, Dispatch<SetStateAction<string>>];
export declare const useFavicon: (initialHref?: string) => {
  href: string;
  set: (favicon: string) => void;
};

5.19 useFileSystemAccess

Hook for reading and writing local files via the File System Access API.

Usage
import { useFileSystemAccess } from "@siberiacancode/reactuse";

const fileSystemAccess = useFileSystemAccess();
Example
import { useFileSystemAccess } from "@siberiacancode/reactuse";

export const FileEditor = () => {
  const fileSystemAccess = useFileSystemAccess({ dataType: "Text" });

  return (
    <div>
      <button type="button" onClick={() => fileSystemAccess.open()}>
        Open
      </button>
      <pre>{fileSystemAccess.data}</pre>
    </div>
  );
};

dataType:

const buf = useFileSystemAccess({ dataType: "ArrayBuffer" });
const blob = useFileSystemAccess({ dataType: "Blob" });
Notes
Type Declarations
export interface FileSystemAccessShowOpenFileOptions {
  excludeAcceptAllOption?: boolean;
  multiple?: boolean;
  types?: Array<{
    description?: string;
    accept: Record<string, string[]>;
  }>;
}
export interface FileSystemAccessShowSaveFileOptions {
  excludeAcceptAllOption?: boolean;
  suggestedName?: string;
  types?: Array<{
    description?: string;
    accept: Record<string, string[]>;
  }>;
}
export type UseFileSystemAccessCommonOptions = Pick<
  FileSystemAccessShowOpenFileOptions,
  "excludeAcceptAllOption" | "types"
>;
export type UseFileSystemAccessShowSaveOptions = Pick<
  FileSystemAccessShowSaveFileOptions,
  "suggestedName"
>;
export type UseFileSystemAccessOptions = UseFileSystemAccessCommonOptions & {
  dataType?: "ArrayBuffer" | "Blob" | "Text";
};
export interface UseFileSystemAccessReturn<Data = string | ArrayBuffer | Blob> {
  data?: Data;
  file?: File;
  lastModified: number;
  name: string;
  size: number;
  supported: boolean;
  type: string;
  create: (createOptions?: UseFileSystemAccessShowSaveOptions) => Promise<Data>;
  open: (openOptions?: UseFileSystemAccessCommonOptions) => Promise<Data>;
  save: (saveOptions?: UseFileSystemAccessShowSaveOptions) => Promise<Data>;
  saveAs: (saveOptions?: UseFileSystemAccessShowSaveOptions) => Promise<Data>;
  set: (data: Data) => void;
  update: () => Promise<Data>;
}
export interface UseFileSystemAccess {
  (): UseFileSystemAccessReturn<string | ArrayBuffer | Blob>;
  (
    options: UseFileSystemAccessOptions & { dataType: "ArrayBuffer" }
  ): UseFileSystemAccessReturn<ArrayBuffer>;
  (
    options: UseFileSystemAccessOptions & { dataType: "Blob" }
  ): UseFileSystemAccessReturn<Blob>;
  (
    options: UseFileSystemAccessOptions & { dataType: "Text" }
  ): UseFileSystemAccessReturn<string>;
  (options?: UseFileSystemAccessOptions): UseFileSystemAccessReturn<
    string | ArrayBuffer | Blob
  >;
}
export declare const useFileSystemAccess: UseFileSystemAccess;

5.20 useFps

Measures frames per second.

Usage
import { useFps } from "@siberiacancode/reactuse";

const fps = useFps();

callback:

const fps = useFps((value) => console.log("fps", value));
Example
const fps = useFps();
return <div>FPS: {fps}</div>;
Notes
Type Declarations
export declare const useFps: (callback?: (fps: number) => void) => number;

5.21 useFullscreen

Controls fullscreen state for an element.

Usage
import { useFullscreen } from "@siberiacancode/reactuse";

const fullscreen = useFullscreen<HTMLDivElement>();
// or
const fullscreen = useFullscreen(targetRef, { initialValue: false });
Example
const fullscreen = useFullscreen<HTMLDivElement>();

return (
  <div ref={fullscreen.ref}>
    <button onClick={() => fullscreen.toggle()}>
      {fullscreen.value ? "Exit" : "Enter"} fullscreen
    </button>
  </div>
);

initialValue:

const fullscreen = useFullscreen<HTMLDivElement>({ initialValue: true });

onEnter:

const fullscreen = useFullscreen<HTMLDivElement>({
  onEnter: () => console.log("enter"),
});

onExit:

const fullscreen = useFullscreen<HTMLDivElement>({
  onExit: () => console.log("exit"),
});
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseFullScreenOptions {
  initialValue?: boolean;
  onEnter?: () => void;
  onExit?: () => void;
}
export interface UseFullScreenReturn {
  value: boolean;
  enter: () => void;
  exit: () => void;
  toggle: () => void;
}
export interface UseFullScreen {
  (target: HookTarget, options?: UseFullScreenOptions): UseFullScreenReturn;
  <Target extends Element>(
    options?: UseFullScreenOptions,
    target?: never
  ): UseFullScreenReturn & { ref: StateRef<Target> };
}
export declare const useFullscreen: UseFullScreen;

5.22 useGamepad

Returns connected gamepads and active status.

Usage
import { useGamepad } from "@siberiacancode/reactuse";

const gamepad = useGamepad();
Example
import { useGamepad } from "@siberiacancode/reactuse";

export const GamepadList = () => {
  const gamepad = useGamepad();
  if (!gamepad.supported) return <div>Not supported</div>;

  const first = gamepad.gamepads[0];

  return (
    <div>
      Connected: {gamepad.gamepads.length}
      <div>Active: {String(gamepad.active)}</div>
      <div>First: {first ? first.id : "none"}</div>
    </div>
  );
};
Notes
Type Declarations
export interface UseGamepadStateReturn {
  active: boolean;
  gamepads: Gamepad[];
  supported: boolean;
}
export declare const useGamepad: () => UseGamepadStateReturn;

5.23 useGeolocation

Keeps the latest browser geolocation reading in React state and exposes controls for one-off reads and watch mode.

Usage
import { useGeolocation } from "@siberiacancode/reactuse";

const geolocation = useGeolocation();

callback:

const geolocation = useGeolocation((position) => {
  console.log(position.coords.latitude);
});
Example
import { useGeolocation } from "@siberiacancode/reactuse";

export const Location = () => {
  const geolocation = useGeolocation({ immediately: false });
  const { value } = geolocation;

  if (value.loading) return <p>Locating...</p>;
  if (value.error) return <p>Permission denied</p>;

  return (
    <div>
      <button onClick={geolocation.start}>Start</button>
      <button onClick={geolocation.stop}>Stop</button>
      <p>
        {value.latitude}, {value.longitude}
      </p>
    </div>
  );
};

get:

const geolocation = useGeolocation({ immediately: false });
geolocation.get();

immediately:

const geolocation = useGeolocation({ immediately: false });

enableHighAccuracy:

const geolocation = useGeolocation({ enableHighAccuracy: true });

maximumAge:

const geolocation = useGeolocation({ maximumAge: 10000 });

timeout:

const geolocation = useGeolocation({ timeout: 5000 });

onChange:

const geolocation = useGeolocation({
  onChange: (position) => console.log(position.coords.latitude),
});

onError:

const geolocation = useGeolocation({
  onError: (error) => console.error(error.message),
});
Notes
Type Declarations
export interface UseGeolocationValue {
  accuracy: number | null;
  altitude: number | null;
  altitudeAccuracy: number | null;
  error: GeolocationPositionError | null;
  heading: number | null;
  latitude: number | null;
  loading: boolean;
  longitude: number | null;
  speed: number | null;
  timestamp: number | null;
}
export interface UseGeolocationReturn {
  value: UseGeolocationValue;
  watching: boolean;
  get: () => void;
  start: () => void;
  stop: () => void;
}
export type UseGeolocationCallback = (position: GeolocationPosition) => void;
export interface UseGeolocationOptions extends PositionOptions {
  immediately?: boolean;
  onChange?: UseGeolocationCallback;
  onError?: (error: GeolocationPositionError) => void;
}
export interface UseGeolocation {
  (
    callback?: UseGeolocationCallback,
    options?: PositionOptions & { immediately?: boolean }
  ): UseGeolocationReturn;
  (options?: UseGeolocationOptions): UseGeolocationReturn;
}
export declare const useGeolocation: UseGeolocation;

5.24 useMeasure

Measures an element's size and position.

Usage
import { useMeasure } from "@siberiacancode/reactuse";

const rect = useMeasure<HTMLDivElement>();
// or
const rect = useMeasure(ref);
Example
const measure = useMeasure<HTMLDivElement>();

return (
  <div ref={measure.ref}>
    Width: {Math.round(measure.width)}px
    <div>Height: {Math.round(measure.height)}px</div>
  </div>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseMeasureReturn = Pick<
  DOMRectReadOnly,
  "bottom" | "height" | "left" | "right" | "top" | "width" | "x" | "y"
>;
export interface UseMeasure {
  (target: HookTarget): UseMeasureReturn;
  <Target extends Element>(target?: never): UseMeasureReturn & {
    ref: StateRef<Target>;
  };
}
export declare const useMeasure: UseMeasure;

5.25 useMediaControls

Provides controls and state for audio/video elements.

Usage
import { useMediaControls } from "@siberiacancode/reactuse";

const media = useMediaControls<HTMLVideoElement>("video.mp4");
// or
const media = useMediaControls(ref, { src: "video.mp4", type: "video/mp4" });
Example
import { useMediaControls } from "@siberiacancode/reactuse";

export const Player = () => {
  const media = useMediaControls<HTMLVideoElement>("video.mp4");

  return (
    <div>
      <video ref={videoMediaControls.ref} src="video.mp4" type="video/mp4" />
      <button onClick={() => media.toggle()}>
        {media.playing ? "Pause" : "Play"}
      </button>
    </div>
  );
};

src:

const media = useMediaControls<HTMLAudioElement>("audio.mp3");

type:

const media = useMediaControls<HTMLVideoElement>({
  src: "video.mp4",
  type: "video/mp4",
});

media:

const media = useMediaControls<HTMLVideoElement>({
  src: "video.mp4",
  media: "(min-width: 800px)",
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseMediaSource {
  media?: string;
  src: string;
  type?: string;
}
export interface UseMediaControlsReturn {
  buffered: [number, number][];
  currentTime: number;
  duration: number;
  ended: boolean;
  muted: boolean;
  playbackRate: number;
  playing: boolean;
  seeking: boolean;
  stalled: boolean;
  volume: number;
  waiting: boolean;
  changePlaybackRate: (rate: number) => void;
  changeVolume: (volume: number) => void;
  mute: () => void;
  pause: () => void;
  play: () => Promise<void>;
  seek: (time: number) => void;
  toggle: () => Promise<void>;
  unmute: () => void;
}
export interface UseMediaControls {
  (target: HookTarget, src: string): UseMediaControlsReturn;
  (target: HookTarget, options: UseMediaSource): UseMediaControlsReturn;
  <Target extends HTMLMediaElement>(src: string): UseMediaControlsReturn & {
    ref: StateRef<Target>;
  };
  <Target extends HTMLMediaElement>(
    options: UseMediaSource
  ): UseMediaControlsReturn & { ref: StateRef<Target> };
}
export declare const useMediaControls: UseMediaControls;

5.26 useMediaQuery

Returns whether a media query matches.

Usage
import { useMediaQuery } from "@siberiacancode/reactuse";

const matches = useMediaQuery("(max-width: 768px)");
Example
import { useMediaQuery } from "@siberiacancode/reactuse";

export const MobileOnly = () => {
  const isMobile = useMediaQuery("(max-width: 768px)");
  return isMobile ? <div>Mobile layout</div> : <div>Desktop layout</div>;
};
Notes
Type Declarations
export declare const useMediaQuery: (query: string) => boolean;

5.27 useMediaStream

Connects camera or microphone capture to a media element while exposing stream lifecycle state and constraint updates.

Usage
import { useMediaStream } from "@siberiacancode/reactuse";

const media = useMediaStream<HTMLVideoElement>();
// or
const media = useMediaStream(videoRef, { constraints: { video: true } });
Example
import { useMediaStream } from "@siberiacancode/reactuse";

export const CameraPreview = () => {
  const media = useMediaStream<HTMLVideoElement>({
    constraints: { video: true, audio: false },
  });

  return (
    <div>
      <video ref={media.ref} autoPlay muted playsInline />
      <button onClick={() => media.start()}>Start</button>
      <button onClick={media.stop}>Stop</button>
    </div>
  );
};

constraints:

const media = useMediaStream<HTMLVideoElement>({
  constraints: { video: true, audio: false },
});

immediately:

const media = useMediaStream(videoRef, { immediately: true });

onError:

const media = useMediaStream({ onError: (error) => console.error(error) });

onStart:

const media = useMediaStream({
  onStart: (stream) => console.log(stream.id),
});

onStop:

const media = useMediaStream({ onStop: () => console.log("stopped") });

apply(constraints):

await media.apply({ video: { width: 1280 } });
Notes
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export interface UseMediaStreamOptions {
  constraints?: MediaStreamConstraints;
  immediately?: boolean;
  onError?: (error: Error) => void;
  onStart?: (stream: MediaStream) => void;
  onStop?: (stream?: MediaStream) => void;
}
export interface UseMediaStreamReturn {
  active: boolean;
  loading: boolean;
  stream?: MediaStream;
  supported: boolean;
  apply: (constraints: MediaStreamConstraints) => Promise<boolean>;
  restart: () => Promise<MediaStream | undefined>;
  start: (constraints?: MediaStreamConstraints) => Promise<MediaStream | undefined>;
  stop: () => void;
}
export interface UseMediaStream {
  (target: HookTarget, options?: UseMediaStreamOptions): UseMediaStreamReturn;
  (options?: UseMediaStreamOptions): UseMediaStreamReturn & {
    ref: StateRef<HTMLVideoElement>;
  };
}
export declare const useMediaStream: UseMediaStream;

5.28 useMemory

Returns the current JS heap memory usage.

Usage
import { useMemory } from "@siberiacancode/reactuse";

const memory = useMemory();

callback:

const memory = useMemory((value) => {
  console.log(value.usedJSHeapSize);
});
Example
import { useMemory } from "@siberiacancode/reactuse";

export const Memory = () => {
  const memory = useMemory();
  if (!memory.supported) return <div>Not supported</div>;

  const used =
    Math.round((memory.value.usedJSHeapSize / 1024 / 1024) * 10) / 10;

  return <div>Heap used: {used} MB</div>;
};
Notes
Type Declarations
export interface UseMemoryReturn {
  supported: boolean;
  value: Performance["memory"];
}
export type UseMemoryCallback = (value: Performance["memory"]) => void;
export declare const useMemory: (
  callback?: UseMemoryCallback
) => UseMemoryReturn;

5.29 useNetwork

Tracks online status and connection information.

Usage
import { useNetwork } from "@siberiacancode/reactuse";

const network = useNetwork();

callback:

const network = useNetwork((value) => {
  console.log(value.online);
});
Example
import { useNetwork } from "@siberiacancode/reactuse";

export const NetworkInfo = () => {
  const network = useNetwork();
  return (
    <div>
      {network.online ? "Online" : "Offline"}
      {network.online && (
        <div>
          Type: {network.type ?? "unknown"} ({network.effectiveType ?? "n/a"})
        </div>
      )}
    </div>
  );
};
Notes
Type Declarations
export interface UseNetworkReturn {
  downlink?: number;
  downlinkMax?: number;
  effectiveType?: "2g" | "3g" | "4g" | "slow-2g";
  online: boolean;
  rtt?: number;
  saveData?: boolean;
  type?:
    | "bluetooth"
    | "cellular"
    | "ethernet"
    | "mixed"
    | "none"
    | "other"
    | "unknown"
    | "wifi"
    | "wimax";
}
export declare const useNetwork: (
  callback?: (value: UseNetworkReturn) => void
) => UseNetworkReturn;

5.30 useNotification

Keeps browser notification permission and the latest notification instance available for UI flows that ask permission before showing messages.

Usage
import { useNotification } from "@siberiacancode/reactuse";

const notification = useNotification();
Example
import { useNotification } from "@siberiacancode/reactuse";

export const NotifyButton = () => {
  const notification = useNotification();

  return (
    <button
      disabled={!notification.supported}
      onClick={async () => {
        if (await notification.trigger()) {
          notification.show({ title: "Build finished" });
        }
      }}
    >
      Notify me
    </button>
  );
};

title:

notification.show({ title: "Build finished" });

NotificationOptions:

notification.show({ title: "New message", body: "Open the inbox" });

onClick:

notification.show({ title: "New message", onClick: () => router.push("/inbox") });

onClose:

notification.show({ title: "Saved", onClose: () => console.log("closed") });

onError:

notification.show({ title: "Sync failed", onError: (event) => console.error(event) });

onShow:

notification.show({ title: "Ready", onShow: () => console.log("shown") });

trigger():

const allowed = await notification.trigger();
if (allowed) notification.show({ title: "Ready" });
Notes
Type Declarations
export interface UseNotificationParams extends NotificationOptions {
  title?: string;
  onClick?: (event: Event) => void;
  onClose?: (event: Event) => void;
  onError?: (event: Event) => void;
  onShow?: (event: Event) => void;
}
export interface UseNotificationReturn {
  notification: Notification | undefined;
  supported: boolean;
  close: () => void;
  show: (params?: UseNotificationParams) => Notification | undefined;
  trigger: () => Promise<boolean>;
}
export declare const useNotification: () => UseNotificationReturn;

5.31 useObjectUrl

Hook that creates and revokes an object URL for a Blob or MediaSource.

Usage
import { useObjectUrl } from "@siberiacancode/reactuse";

const { value } = useObjectUrl(blob);
Example
import { useObjectUrl } from "@siberiacancode/reactuse";

interface PreviewProps {
  blob: Blob;
}

export const Preview = ({ blob }: PreviewProps) => {
  const objectUrl = useObjectUrl(blob);
  return <img src={objectUrl.value} alt="" />;
};
Notes
Type Declarations
export interface UseObjectUrlReturn {
  value?: string;
  revoke: () => void;
  set: (object: Blob | MediaSource) => void;
}
export declare const useObjectUrl: <
  Value extends Blob | MediaSource | undefined
>(
  object?: Value
) => UseObjectUrlReturn;

5.32 useOnline

Returns whether the user is online.

Usage
import { useOnline } from "@siberiacancode/reactuse";

const online = useOnline();
Example
import { useOnline } from "@siberiacancode/reactuse";

export const Status = () => {
  const online = useOnline();
  return (
    <div>
      {online ? "Online" : "Offline"}
      {!online && <div>Changes will sync when you reconnect.</div>}
    </div>
  );
};
Notes
Type Declarations
export declare const useOnline: () => boolean;

5.33 useOtpCredential

Requests an OTP credential from the user agent.

Usage
import { useOtpCredential } from "@siberiacancode/reactuse";

const otp = useOtpCredential();
Example
const otp = useOtpCredential();

return (
  <button onClick={() => otp.get()}>
    {otp.supported ? "Read SMS code" : "Not supported"}
  </button>
);

onSuccess:

const otp = useOtpCredential({
  onSuccess: (credential) => console.log(credential),
});

onError:

const otp = useOtpCredential({
  onError: (error) => console.error(error),
});
Notes
Type Declarations
export type UseOtpCredentialCallback = (otp: Credential | null) => void;
export interface UseOtpCredentialParams {
  onError?: (error: any) => void;
  onSuccess?: (credential: Credential | null) => void;
}
export interface UseOtpCredentialReturn {
  abort: AbortController["abort"];
  supported: boolean;
  get: () => Promise<Credential | null>;
}
export interface UseOtpCredential {
  (callback?: UseOtpCredentialCallback): UseOtpCredentialReturn;
  (params?: UseOtpCredentialParams): UseOtpCredentialReturn;
}
export declare const useOtpCredential: UseOtpCredential;

5.34 usePermission

Tracks a browser permission query so UI can react when access is granted, prompted, or denied.

Usage
import { usePermission } from "@siberiacancode/reactuse";

const permission = usePermission("microphone");
Example
import { usePermission } from "@siberiacancode/reactuse";

export const CameraPermission = () => {
  const permission = usePermission("camera", (state) => console.log(state));

  return <div>{permission.supported ? permission.state : "unsupported"}</div>;
};

onChange:

const permission = usePermission("notifications", {
  onChange: (state) => console.log(state),
});

name:

const permission = usePermission("microphone");
Notes
Type Declarations
export type UsePermissionName =
  | "accelerometer"
  | "accessibility-events"
  | "ambient-light-sensor"
  | "background-sync"
  | "camera"
  | "clipboard-read"
  | "clipboard-write"
  | "gyroscope"
  | "local-fonts"
  | "magnetometer"
  | "microphone"
  | "notifications"
  | "payment-handler"
  | "persistent-storage"
  | "push"
  | "speaker"
  | PermissionName;
export type UsePermissionCallback = (state: PermissionState) => void;
export interface UsePermissionOptions {
  onChange?: UsePermissionCallback;
}
export interface UsePermissionReturn {
  state: PermissionState;
  supported: boolean;
  query: () => Promise<PermissionState>;
}
export interface UsePermission {
  (name: UsePermissionName, callback?: UsePermissionCallback): UsePermissionReturn;
  (name: UsePermissionName, options?: UsePermissionOptions): UsePermissionReturn;
}
export declare const usePermission: UsePermission;

5.35 usePictureInPicture

Controls Picture-in-Picture mode for video elements.

Usage
import { usePictureInPicture } from "@siberiacancode/reactuse";

const pip = usePictureInPicture<HTMLVideoElement>();
// or
const pip = usePictureInPicture(ref, { onEnter: () => {} });
Example
import { usePictureInPicture } from "@siberiacancode/reactuse";

const pip = usePictureInPicture<HTMLVideoElement>();
return (
  <div>
    <video ref={pip.ref} src="/video.mp4" controls />
    <button onClick={() => pip.toggle()}>
      {pip.open ? "Exit" : "Enter"} PiP
    </button>
  </div>
);

onEnter:

Enter callback.

const pip = usePictureInPicture<HTMLVideoElement>({
  onEnter: () => console.log("enter"),
});

onExit:

Exit callback.

const pip = usePictureInPicture<HTMLVideoElement>({
  onExit: () => console.log("exit"),
});
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UsePictureInPictureOptions {
  onEnter?: () => void;
  onExit?: () => void;
}
export interface UsePictureInPictureReturn {
  open: boolean;
  supported: boolean;
  enter: () => Promise<void>;
  exit: () => Promise<void>;
  toggle: () => Promise<void>;
}
export interface UsePictureInPicture {
  (
    target: HookTarget,
    options?: UsePictureInPictureOptions
  ): UsePictureInPictureReturn;
  (options?: UsePictureInPictureOptions): UsePictureInPictureReturn & {
    ref: StateRef<HTMLVideoElement>;
  };
}
export declare const usePictureInPicture: UsePictureInPicture;

5.36 usePointerLock

Provides reactive pointer lock controls.

Usage
import { usePointerLock } from "@siberiacancode/reactuse";

const pointerLock = usePointerLock();
Example
import { usePointerLock } from "@siberiacancode/reactuse";

export const Canvas = () => {
  const pointer = usePointerLock();
  return <div onClick={pointer.lock}>Click to lock</div>;
};
Notes
Type Declarations
import type { MouseEvent } from "react";

interface UsePointerLockReturn {
  element?: Element;
  supported: boolean;
  lock: (event: MouseEvent) => void;
  unlock: () => boolean;
}
export declare const usePointerLock: () => UsePointerLockReturn;

5.37 usePostMessage

Receives and posts messages between windows/frames.

Usage
import { usePostMessage } from "@siberiacancode/reactuse";

const postMessage = usePostMessage("*", (message) => console.log(message));
Example
const postMessage = usePostMessage<string>("*", (message) => {
  console.log("received", message);
});

return <button onClick={() => postMessage("ping")}>Send</button>;
Type Declarations
export type UsePostMessageOrigin = string | "*" | string[];
export type UsePostMessageReturn<Message> = (message: Message) => void;
export declare const usePostMessage: <Message>(
  origin: UsePostMessageOrigin,
  callback: (message: Message, event: MessageEvent<Message>) => void
) => UsePostMessageReturn<Message>;

5.38 useRaf

Runs a callback on each animation frame.

Usage
import { useRaf } from "@siberiacancode/reactuse";

const raf = useRaf(() => console.log("callback"));
Example
const [ticks, setTicks] = useState(0);
const raf = useRaf(() => setTicks((value) => value + 1));

return <button onClick={() => raf.pause()}>Ticks: {ticks}</button>;

delay:

const raf = useRaf(() => console.log("callback"), { delay: 100 });

enabled:

const raf = useRaf(() => console.log("callback"), { enabled: false });
Notes
Type Declarations
export interface UseRafParams {
  delta: number;
  timestamp: DOMHighResTimeStamp;
}
export type UseRafCallback = (params: UseRafParams) => void;
export interface UseRafOptions {
  delay?: number;
  enabled?: boolean;
}
export interface UseRafReturn {
  active: boolean;
  pause: () => void;
  resume: () => void;
}
export declare const useRaf: (
  callback: UseRafCallback,
  options?: UseRafOptions
) => UseRafReturn;

5.39 useShare

Triggers the native share dialog.

Usage
import { useShare } from "@siberiacancode/reactuse";

const share = useShare();
Example
import { useShare } from "@siberiacancode/reactuse";

const share = useShare();
return (
  <button
    onClick={() =>
      share.trigger({
        title: "Design notes",
        text: "Check this out",
        url: "https://example.com",
      })
    }
    disabled={!share.supported}
  >
    Share
  </button>
);

text:

const share = useShare({ text: "Hello" });

title:

const share = useShare({ title: "Article" });

url:

const share = useShare({ url: "https://example.com" });

files:

const share = useShare({ files: [file] });
Notes
Type Declarations
export interface UseShareParams {
  files?: File[];
  text?: string;
  title?: string;
  url?: string;
}
export interface UseShareReturn {
  supported: boolean;
  trigger: (shareParams: ShareData) => Promise<void>;
}
export declare const useShare: (params?: UseShareParams) => UseShareReturn;

5.40 useSpeechRecognition

Turns browser speech recognition into React state so voice input can be started, stopped, aborted, and rendered as transcript text.

Usage
import { useSpeechRecognition } from "@siberiacancode/reactuse";

const speech = useSpeechRecognition();
Example
import { useSpeechRecognition } from "@siberiacancode/reactuse";

export const VoiceNote = () => {
  const speech = useSpeechRecognition({ language: "en-US" });

  if (!speech.supported) return <div>Not supported</div>;

  return (
    <div>
      <button onClick={() => speech.toggle()}>
        {speech.listening ? "Stop" : "Start"}
      </button>
      <div>Transcript: {speech.transcript}</div>
    </div>
  );
};

continuous:

const speech = useSpeechRecognition({ continuous: true });

interimResults:

const speech = useSpeechRecognition({ interimResults: true });

language:

const speech = useSpeechRecognition({ language: "ru-RU" });

maxAlternatives:

const speech = useSpeechRecognition({ maxAlternatives: 3 });

abort:

const speech = useSpeechRecognition();
speech.abort();

grammars:

const speech = useSpeechRecognition({ grammars });

onStart:

const speech = useSpeechRecognition({ onStart: () => console.log("start") });

onEnd:

const speech = useSpeechRecognition({ onEnd: () => console.log("end") });

onError:

const speech = useSpeechRecognition({
  onError: (error) => console.error(error),
});

onResult:

const speech = useSpeechRecognition({
  onResult: (event) => console.log(event),
});
Notes
Type Declarations
export interface UseSpeechRecognitionOptions {
  continuous?: SpeechRecognition["continuous"];
  grammars?: SpeechRecognition["grammars"];
  interimResults?: SpeechRecognition["interimResults"];
  language?: SpeechRecognition["lang"];
  maxAlternatives?: SpeechRecognition["maxAlternatives"];
  onEnd?: () => void;
  onError?: (error: SpeechRecognitionErrorEvent) => void;
  onResult?: (event: SpeechRecognitionEvent) => void;
  onStart?: () => void;
}
export interface UseSpeechRecognitionReturn {
  error: SpeechRecognitionErrorEvent | null;
  final: boolean;
  listening: boolean;
  recognition?: SpeechRecognition;
  supported: boolean;
  transcript: string;
  start: () => void;
  stop: () => void;
  abort: () => void;
  toggle: (value?: boolean) => void;
}
export declare const useSpeechRecognition: (
  options?: UseSpeechRecognitionOptions
) => UseSpeechRecognitionReturn;

5.41 useSpeechSynthesis

Turns text into spoken output while keeping playback status, errors, and pause/resume controls in React state.

Usage
import { useSpeechSynthesis } from "@siberiacancode/reactuse";

const speech = useSpeechSynthesis();
Example
import { useSpeechSynthesis } from "@siberiacancode/reactuse";

export const Reader = () => {
  const speech = useSpeechSynthesis({ text: "Hello from Reactuse" });

  if (!speech.supported) return <div>Not supported</div>;

  return (
    <button onClick={() => speech.speak()}>
      {speech.playing ? "Speaking..." : "Speak"}
    </button>
  );
};

text:

const speech = useSpeechSynthesis({ text: "Hello" });

lang:

const speech = useSpeechSynthesis({ lang: "en-US" });

pitch:

const speech = useSpeechSynthesis({ pitch: 1.5 });

rate:

const speech = useSpeechSynthesis({ rate: 0.8 });

voice:

const speech = useSpeechSynthesis({ voice });

volume:

const speech = useSpeechSynthesis({ volume: 0.6 });

speak(text):

const speech = useSpeechSynthesis();
speech.speak("Read this sentence");
Notes
Type Declarations
export type UseSpeechSynthesisStatus = "end" | "init" | "pause" | "play";
export interface UseSpeechSynthesisOptions {
  lang?: string;
  pitch?: number;
  rate?: number;
  text?: string;
  voice?: SpeechSynthesisVoice | null;
  volume?: number;
}
export interface UseSpeechSynthesisReturn {
  error: SpeechSynthesisErrorEvent | undefined;
  playing: boolean;
  status: UseSpeechSynthesisStatus;
  supported: boolean;
  utterance: SpeechSynthesisUtterance | undefined;
  pause: () => void;
  resume: () => void;
  speak: (text?: string) => void;
  stop: () => void;
  toggle: (value?: boolean) => void;
}
export declare const useSpeechSynthesis: (
  options?: UseSpeechSynthesisOptions
) => UseSpeechSynthesisReturn;

5.42 useVibrate

Triggers vibration with optional intervals.

Usage
import { useVibrate } from "@siberiacancode/reactuse";

const vibrate = useVibrate(1000);
Example
import { useVibrate } from "@siberiacancode/reactuse";

export const HapticButton = () => {
  const vibrate = useVibrate(200);

  return <button onClick={() => vibrate.trigger()}>Vibrate</button>;
};

pattern:

const vibrate = useVibrate([200, 100, 200]);

interval:

const vibrate = useVibrate(200, 1000);
Notes
Type Declarations
export type UseVibratePattern = number | number[];
export interface UseVibrateReturn {
  supported: boolean;
  vibrating: boolean;
  pause: () => void;
  resume: () => void;
  start: (interval: number) => void;
  trigger: (pattern?: UseVibratePattern) => void;
}
export declare const useVibrate: (
  pattern: UseVibratePattern,
  interval?: number
) => UseVibrateReturn;

5.43 useVirtualKeyboard

Tracks virtual keyboard state and exposes controls.

Usage
import { useVirtualKeyboard } from "@siberiacancode/reactuse";

const keyboard = useVirtualKeyboard();
Example
import { useVirtualKeyboard } from "@siberiacancode/reactuse";

export const KeyboardControls = () => {
  const keyboard = useVirtualKeyboard();

  return (
    <div>
      <button onClick={() => keyboard.show()}>Show</button>
      <button onClick={() => keyboard.hide()}>Hide</button>
      <div>Open: {String(keyboard.opened)}</div>
    </div>
  );
};

initialValue:

const keyboard = useVirtualKeyboard(true);
Notes
Type Declarations
export interface UseVirtualKeyboardReturn {
  opened: boolean;
  supported: boolean;
  changeOverlaysContent: (overlaysContent: boolean) => void;
  hide: () => void;
  show: () => void;
}
export declare const useVirtualKeyboard: (
  initialValue?: boolean
) => UseVirtualKeyboardReturn;

5.44 useWakeLock

Controls the Wake Lock API state.

Usage
import { useWakeLock } from "@siberiacancode/reactuse";

const wake = useWakeLock();
Example
import { useWakeLock } from "@siberiacancode/reactuse";

export const WakeLockToggle = () => {
  const wake = useWakeLock();

  return (
    <button onClick={() => (wake.active ? wake.release() : wake.request())}>
      {wake.active ? "Release" : "Keep awake"}
    </button>
  );
};

immediately:

const wake = useWakeLock({ immediately: true });

type:

const wake = useWakeLock({ type: "screen" });
Notes
Type Declarations
export interface UseWakeLockOptions {
  immediately?: boolean;
  type?: WakeLockType;
}
export interface UseWakeLockReturn {
  active: boolean;
  supported: boolean;
  release: () => Promise<void>;
  request: () => Promise<void>;
}
export declare const useWakeLock: (
  options?: UseWakeLockOptions
) => UseWakeLockReturn;

5.45 useWebSocket

Keeps a component connected to a WebSocket endpoint while exposing a small control surface for manual open/close, message sending, retries, and connection lifecycle reactions.

Usage
import { useWebSocket } from "@siberiacancode/reactuse";

const socket = useWebSocket("wss://example.com");
Example
import { useWebSocket } from "@siberiacancode/reactuse";

export const SocketPing = () => {
  const socket = useWebSocket("wss://example.com", {
    heartbeat: (ws) => ws.send("ping"),
    heartbeatDelay: 30000,
  });

  return (
    <button onClick={() => socket.send("hello")}>Status: {socket.status}</button>
  );
};

url:

const socket = useWebSocket(() => `wss://example.com/${roomId}`);

heartbeat:

const socket = useWebSocket("wss://example.com", {
  heartbeat: (webSocket) => webSocket.send("ping"),
});

heartbeatDelay:

const socket = useWebSocket("wss://example.com", { heartbeatDelay: 30000 });

immediately:

const socket = useWebSocket("wss://example.com", { immediately: false });
socket.open();

protocols:

const socket = useWebSocket("wss://example.com", { protocols: ["soap"] });

onClose:

const socket = useWebSocket("wss://example.com", {
  onClose: (event) => console.log(event.code),
});

onConnected:

const socket = useWebSocket("wss://example.com", {
  onConnected: (webSocket) => console.log(webSocket.readyState),
});

onError:

const socket = useWebSocket("wss://example.com", {
  onError: (event) => console.error(event),
});

onMessage:

const socket = useWebSocket("wss://example.com", {
  onMessage: (event) => console.log(event.data),
});

retry:

const socket = useWebSocket("wss://example.com", {
  retry: (failureCount) => failureCount < 3,
});

retryDelay:

const socket = useWebSocket("wss://example.com", {
  retry: 3,
  retryDelay: 1000,
});
Notes
Type Declarations
export type UseWebSocketUrl = (() => string) | string;
export interface UseWebSocketOptions {
  heartbeatDelay?: number;
  immediately?: boolean;
  protocols?: Array<"soap" | "wasm">;
  retry?: ((failureCount: number, event: CloseEvent) => boolean) | boolean | number;
  retryDelay?: number;
  heartbeat?: (webSocket: WebSocket) => void;
  onClose?: (event: CloseEvent, webSocket: WebSocket) => void;
  onConnected?: (webSocket: WebSocket) => void;
  onError?: (event: Event, webSocket: WebSocket) => void;
  onMessage?: (event: MessageEvent, webSocket: WebSocket) => void;
}
export type UseWebSocketStatus = "closed" | "connected" | "connecting" | "failed";
export interface UseWebSocketReturn {
  client?: WebSocket;
  close: WebSocket["close"];
  send: WebSocket["send"];
  status: UseWebSocketStatus;
  open: () => void;
}
export declare const useWebSocket: (
  url: UseWebSocketUrl,
  options?: UseWebSocketOptions
) => UseWebSocketReturn;

5.46 useWebWorker

Keeps a Web Worker connected to React state so components can post messages, restart work, terminate it, and render the latest result or error.

Usage
import { useWebWorker } from "@siberiacancode/reactuse";

const worker = useWebWorker<number>("/worker.js");
Example
import { useWebWorker } from "@siberiacancode/reactuse";

export const WorkerCounter = () => {
  const worker = useWebWorker<number>("/counter-worker.js");

  return (
    <div>
      <button onClick={() => worker.post("next")}>Next</button>
      <span>{worker.data ?? 0}</span>
      <button onClick={worker.terminate}>Stop</button>
    </div>
  );
};

source as URL:

const worker = useWebWorker(new URL("./worker.ts", import.meta.url));

source as Worker:

const worker = useWebWorker(new Worker("/worker.js"));

WorkerOptions:

const worker = useWebWorker("/worker.js", { type: "module" });

onError:

const worker = useWebWorker("/worker.js", {
  onError: (event) => console.error(event),
});

onMessage:

const worker = useWebWorker<number>("/worker.js", {
  onMessage: (data) => console.log(data),
});
Notes
Type Declarations
export type UseWebWorkerSource = string | URL | Worker;
export interface UseWebWorkerOptions<Data = unknown> extends WorkerOptions {
  onError?: (event: Event) => void;
  onMessage?: (data: Data, event: MessageEvent<Data>) => void;
}
export interface UseWebWorkerReturn<Data = unknown> {
  data?: Data;
  error?: Event;
  post: Worker["postMessage"];
  terminated: boolean;
  restart: () => void;
  terminate: () => void;
}
export declare const useWebWorker: <Data = unknown>(
  source: UseWebWorkerSource,
  options?: UseWebWorkerOptions<Data>
) => UseWebWorkerReturn<Data>;

5.47 useWebWorkerCallback

Runs a self-contained function off the main thread and returns a promise-based runner for component code.

Usage
import { useWebWorkerCallback } from "@siberiacancode/reactuse";

const worker = useWebWorkerCallback((input: number) => input * 2);
Example
import { useWebWorkerCallback } from "@siberiacancode/reactuse";

export const HeavyCompute = () => {
  const worker = useWebWorkerCallback((count: number) => {
    let total = 0;
    for (let index = 0; index < count; index++) total += index;
    return total;
  });

  return (
    <button
      disabled={worker.pending}
      onClick={async () => console.log(await worker.run(1000000))}
    >
      Run
    </button>
  );
};

callback:

const worker = useWebWorkerCallback((value: number) => value * 2);

run(...args):

const doubled = await worker.run(21);
Notes
Type Declarations
export interface UseWebWorkerCallbackReturn<
  Callback extends (...args: any[]) => any
> {
  pending: boolean;
  run: (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>>;
  terminate: () => void;
}
export declare const useWebWorkerCallback: <
  Callback extends (...args: any[]) => any
>(
  callback: Callback
) => UseWebWorkerCallbackReturn<Callback>;

6.1 useBatchedCallback

Batches calls and forwards them to a callback.

Usage
import { useBatchedCallback } from "@siberiacancode/reactuse";

const batched = useBatchedCallback((batch) => console.log(batch), { size: 5 });
Example
import { useBatchedCallback } from "@siberiacancode/reactuse";

export const Logger = () => {
  const batched = useBatchedCallback((batch) => {
    console.log("batch", batch);
  }, { size: 3, delay: 1000 });

  return (
    <div>
      <button onClick={() => batched("click")}>Queue</button>
      <button onClick={() => batched.flush()}>Flush</button>
    </div>
  );
};
Notes
  • Call batched.flush() to send the current batch immediately.
  • Call batched.cancel() to clear pending calls.
Type Declarations
export type BatchedCallback<Params extends unknown[]> = ((
  ...args: Params
) => void) & {
  flush: () => void;
  cancel: () => void;
};
export interface UseBatchedCallbackOptions {
  delay?: number;
  size: number;
}
export declare const useBatchedCallback: <Params extends unknown[]>(
  callback: (batch: Params[]) => void,
  options: UseBatchedCallbackOptions
) => BatchedCallback<Params>;

6.2 useConst

Returns a constant value initialized once.

Usage
import { useConst } from "@siberiacancode/reactuse";

const value = useConst("value");
Example
const id = useConst(() => crypto.randomUUID());
const config = useConst(() => ({ retry: 2 }));
return (
  <div>
    {id} (retry: {config.retry})
  </div>
);
Type Declarations
export declare const useConst: <Value>(
  initialValue: (() => Value) | Value
) => Value;

6.3 useDebounceCallback

Creates a debounced callback with a cancel method.

Usage
import { useDebounceCallback } from "@siberiacancode/reactuse";

const debounced = useDebounceCallback(() => console.log("callback"), 500);
Example
const onSearch = useDebounceCallback((value: string) => {
  console.log(value);
}, 300);

return (
  <div>
    <input onChange={(event) => onSearch(event.target.value)} />
    <button onClick={() => onSearch.cancel()}>Cancel</button>
  </div>
);
Type Declarations
export type DebouncedCallback<Params extends unknown[]> = ((
  ...args: Params
) => void) & {
  cancel: () => void;
};
export declare const useDebounceCallback: <Params extends unknown[], Return>(
  callback: (...args: Params) => Return,
  delay: number
) => DebouncedCallback<Params>;

6.4 useDebounceEffect

Runs an effect after a delay when dependencies change.

Usage
import { useDebounceEffect } from "@siberiacancode/reactuse";

useDebounceEffect(() => console.log("effect"), 500, [value]);
Example
import { useDebounceEffect } from "@siberiacancode/reactuse";

interface SearchProps {
  query: string;
}

export const Search = ({ query }: SearchProps) => {
  useDebounceEffect(() => console.log("fetch", query), 300, [query]);

  return <div>{query}</div>;
};
Type Declarations
import type { DependencyList, EffectCallback } from "react";

export declare const useDebounceEffect: (
  effect: EffectCallback,
  delay: number,
  deps?: DependencyList
) => void;

6.5 useDebounceState

Creates a debounced state setter.

Usage
import { useDebounceState } from "@siberiacancode/reactuse";

const [debounced, setDebounced] = useDebounceState(value, 500);
Example
import { useDebounceState } from "@siberiacancode/reactuse";
import { useState } from "react";

export const DebouncedInput = () => {
  const [value, setValue] = useState("");
  const [debounced, setDebounced] = useDebounceState(value, 300);

  return (
    <div>
      <input
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
          setDebounced(event.target.value);
        }}
      />
      <div>Debounced: {debounced}</div>
    </div>
  );
};
Type Declarations
export declare const useDebounceState: <Value>(
  initialValue: Value,
  delay: number
) => readonly [Value, (value: Value) => void];

6.6 useDebounceValue

Returns a debounced version of a value.

Usage
import { useDebounceValue } from "@siberiacancode/reactuse";

const debounced = useDebounceValue(value, 500);
Example
import { useDebounceValue } from "@siberiacancode/reactuse";
import { useState } from "react";

export const Search = () => {
  const [value, setValue] = useState("");
  const debounced = useDebounceValue(value, 300);

  return (
    <>
      <input value={value} onChange={(event) => setValue(event.target.value)} />
      <div>Query: {debounced || "..."}</div>
    </>
  );
};
Type Declarations
export declare const useDebounceValue: <Value>(
  value: Value,
  delay: number
) => Value;

6.7 useDevicePixelRatio

Returns the current device pixel ratio.

Usage
import { useDevicePixelRatio } from "@siberiacancode/reactuse";

const devicePixelRatio = useDevicePixelRatio();
Example
const devicePixelRatio = useDevicePixelRatio();
if (!devicePixelRatio.supported) return <div>Not supported</div>;

return <div>{String(devicePixelRatio.value)}</div>;
Notes
Type Declarations
export type UseDevicePixelRatioCallback = (value: number) => void;
export interface UseDevicePixelRatioReturn {
  supported: boolean;
  value: number;
}
export declare const useDevicePixelRatio: (
  callback?: UseDevicePixelRatioCallback
) => UseDevicePixelRatioReturn;

6.8 useEvent

Returns a stable callback reference that always calls the latest handler.

Usage
import { useEvent } from "@siberiacancode/reactuse";

const onClick = useEvent(() => console.log("clicked"));
Example
import { useEvent } from "@siberiacancode/reactuse";
import { useState, useEffect } from "react";

export const Button = () => {
  const [count, setCount] = useState(0);
  const onRerender = useEvent(() => setCount(count++));

  useEffect(() => {
    onRerender();
  });
};
Type Declarations
export declare const useEvent: <Params extends unknown[], Return>(
  callback: (...args: Params) => Return
) => (...args: Params) => Return;

6.9 useLastChanged

Records the timestamp of the last change.

Usage
import { useLastChanged } from "@siberiacancode/reactuse";

const lastChanged = useLastChanged(value);
Example

initialValue:

Custom initial timestamp.

const lastChanged = useLastChanged(value, { initialValue: 0 });
console.log(lastChanged);
Type Declarations
export interface UseLastChangedOptions {
  initialValue?: number;
}
export declare const useLastChanged: (
  source: any,
  options?: UseLastChangedOptions
) => number | null;

6.10 useLatest

Returns a stable ref that always points to the latest value.

Usage
import { useLatest } from "@siberiacancode/reactuse";

const latest = useLatest(value);
Example
Type Declarations
import type { RefObject } from "react";

export interface UseLatestReturn<Value> {
  ref: RefObject<Value>;
  value: Value;
}
export declare const useLatest: <Value>(value: Value) => UseLatestReturn<Value>;

6.11 usePrevious

Returns the previous value.

Usage
import { usePrevious } from "@siberiacancode/reactuse";

const prev = usePrevious(value);
Example

equality:

Custom compare.

const prev = usePrevious(value, {
  equality: (a, b) => a.id === b.id,
});
console.log(prev);
Type Declarations
export interface UsePreviousOptions<Value> {
  equality: (a: Value, b: Value) => boolean;
}
export declare const usePrevious: <Value>(
  value: Value,
  options?: UsePreviousOptions<Value>
) => Value | undefined;

6.12 useThrottleCallback

Creates a throttled callback with a cancel method.

Usage
import { useThrottleCallback } from "@siberiacancode/reactuse";

const throttled = useThrottleCallback(() => console.log("callback"), 500);
Example
import { useThrottleCallback } from "@siberiacancode/reactuse";

export const ScrollLogger = () => {
  const onScroll = useThrottleCallback(() => console.log("scroll"), 200);

  return (
    <div onScroll={onScroll}>
      Scroll me
      <button onClick={() => onScroll.cancel()}>Cancel</button>
    </div>
  );
};
Type Declarations
export type ThrottledCallback<Params extends unknown[]> = ((
  ...args: Params
) => void) & {
  cancel: () => void;
};
export declare const useThrottleCallback: <Params extends unknown[], Return>(
  callback: (...args: Params) => Return,
  delay: number
) => ThrottledCallback<Params>;

6.13 useThrottleEffect

Runs an effect at most once per delay period when dependencies change.

Usage
import { useThrottleEffect } from "@siberiacancode/reactuse";

useThrottleEffect(() => console.log("effect"), 500, [value]);
Example
import { useThrottleEffect } from "@siberiacancode/reactuse";

export const Tracker = ({ value }: { value: number }) => {
  useThrottleEffect(
    () => {
      console.log(value);
    },
    1000,
    [value]
  );

  return <div>Value: {value}</div>;
};
Type Declarations
import type { DependencyList, EffectCallback } from "react";

export declare const useThrottleEffect: (
  effect: EffectCallback,
  delay: number,
  deps?: DependencyList
) => void;

6.14 useThrottleState

Creates a throttled state setter.

Usage
import { useThrottleState } from "@siberiacancode/reactuse";

const [throttled, setThrottled] = useThrottleState(value, 500);
Example
import { useThrottleState } from "@siberiacancode/reactuse";
import { useState } from "react";

export const ThrottledInput = () => {
  const [value, setValue] = useState("");
  const [throttled, setThrottled] = useThrottleState(value, 300);

  return (
    <div>
      <input
        value={value}
        onChange={(e) => {
          setValue(e.target.value);
          setThrottled(e.target.value);
        }}
      />
      <div>Throttled: {throttled}</div>
    </div>
  );
};
Type Declarations
export declare const useThrottleState: <Value>(
  initialValue: Value,
  delay: number
) => readonly [Value, (value: Value) => void];

6.15 useThrottleValue

Returns a throttled version of a value.

Usage
import { useThrottleValue } from "@siberiacancode/reactuse";

const throttled = useThrottleValue(value, 500);
Example
import { useThrottleValue } from "@siberiacancode/reactuse";
import { useState } from "react";

export const Search = () => {
  const [value, setValue] = useState("");
  const throttled = useThrottleValue(value, 300);

  return (
    <>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <div>Query: {throttled || "..."}</div>
    </>
  );
};
Type Declarations
export declare const useThrottleValue: <Value>(
  value: Value,
  delay: number
) => Value;

7. State

7.1 useBoolean

Manages a boolean state with a toggle helper.

Usage
import { useBoolean } from "@siberiacancode/reactuse";

const [value, toggle] = useBoolean();
Example
import { useBoolean } from "@siberiacancode/reactuse";

export const Toggle = () => {
  const [value, toggle] = useBoolean();
  return <button onClick={() => toggle()}>{String(value)}</button>;
};

initialValue:

const [value, toggle] = useBoolean(true);
Type Declarations
export type UseBooleanReturn = [
  value: boolean,
  toggle: (value?: boolean) => void
];
export declare const useBoolean: (initialValue?: boolean) => UseBooleanReturn;

7.2 useControllableState

Supports controlled and uncontrolled state patterns.

Usage
import { useControllableState } from "@siberiacancode/reactuse";

const [value, setValue, isControlled] = useControllableState({
  initialValue: "draft",
});
Example
import type { ComponentProps } from "react";
import { useControllableState } from "@siberiacancode/reactuse";

type NameFieldProps = ComponentProps<"input">;

export const NameField = ({ value, onChange }: NameFieldProps) => {
  const [current, setCurrent] = useControllableState({
    value,
    initialValue: "",
    onChange,
  });

  return (
    <input
      value={current}
      onChange={(event) => setCurrent(event.target.value)}
    />
  );
};

value:

const [value, setValue] = useControllableState({ value: props.value });

initialValue:

const [value, setValue] = useControllableState({ initialValue: "draft" });

onChange:

const [value, setValue] = useControllableState({
  initialValue: "draft",
  onChange: (value) => console.log(value),
});
Type Declarations
export interface UseControllableStateOptions<Value> {
  initialValue?: Value;
  value?: Value;
  onChange?: (value: Value) => void;
}
export type UseControllableStateReturn<Value> = [
  value: Value,
  setValue: (nextValue: ((prevValue: Value) => Value) | Value) => void,
  isControlled: boolean
];
export declare function useControllableState<Value>(
  options: UseControllableStateOptions<Value>
): UseControllableStateReturn<Value>;

7.3 useCookie

Reads and writes a cookie value.

Usage
import { useCookie } from "@siberiacancode/reactuse";

const cookie = useCookie("theme", "");
Example
const themeCookie = useCookie<"light" | "dark">("theme", {
  initialValue: "light",
});

return (
  <button
    onClick={() =>
      themeCookie.set(themeCookie.value === "light" ? "dark" : "light")
    }
  >
    Theme: {themeCookie.value}
  </button>
);

domain:

const cookie = useCookie("theme", { domain: ".example.com" });

expires:

const cookie = useCookie("theme", { expires: new Date(Date.now() + 86400000) });

httpOnly:

const cookie = useCookie("theme", { httpOnly: true });

initialValue:

const cookie = useCookie("theme", { initialValue: "" });

maxAge:

const cookie = useCookie("theme", { maxAge: 3600 });

path:

const cookie = useCookie("theme", { path: "/" });

sameSite:

const cookie = useCookie("theme", { sameSite: "Lax" });

secure:

const cookie = useCookie("theme", { secure: true });

deserializer:

const cookie = useCookie("user", {
  deserializer: (value) => JSON.parse(value),
});

serializer:

const cookie = useCookie("user", {
  serializer: (value) => JSON.stringify(value),
});
Type Declarations
export interface RemoveCookieParams {
  domain?: string;
  expires?: Date;
  maxAge?: number;
  path?: string;
  sameSite?: "Lax" | "None" | "Strict";
  secure?: boolean;
}
export interface SetCookieParams {
  domain?: string;
  expires?: Date;
  httpOnly?: boolean;
  maxAge?: number;
  path?: string;
  sameSite?: "Lax" | "None" | "Strict";
  secure?: boolean;
}
export type UseCookieInitialValue<Value> = (() => Value) | Value;
export interface UseCookieOptions<Value> {
  domain?: string;
  expires?: Date;
  httpOnly?: boolean;
  initialValue?: UseCookieInitialValue<Value>;
  maxAge?: number;
  path?: string;
  sameSite?: "Lax" | "None" | "Strict";
  secure?: boolean;
  deserializer?: (value: string) => Value;
  serializer?: (value: Value) => string;
}
export interface UseCookieReturn<Value> {
  value: Value;
  remove: (options?: RemoveCookieParams) => void;
  set: (value: Value, options?: SetCookieParams) => void;
}
export interface UseCookie {
  <Value>(
    key: string,
    options: UseCookieOptions<Value> & {
      initialValue: UseCookieInitialValue<Value>;
    }
  ): UseCookieReturn<Value>;
  <Value>(key: string, options?: UseCookieOptions<Value>): UseCookieReturn<
    Value | undefined
  >;
  <Value>(
    key: string,
    initialValue: UseCookieInitialValue<Value>
  ): UseCookieReturn<Value>;
  <Value>(key: string): UseCookieReturn<Value | undefined>;
}
export declare const useCookie: UseCookie;

7.4 useCookies

Manages all cookies as a single object.

Usage
import { useCookies } from "@siberiacancode/reactuse";

const cookies = useCookies();
Example
const cookies = useCookies<{ theme: string }>();

return (
  <button onClick={() => cookies.set("theme", "dark")}>
    Theme: {cookies.value.theme ?? "none"}
  </button>
);

deserializer:

const cookies = useCookies({
  deserializer: (value) => JSON.parse(value),
});

serializer:

const cookies = useCookies({
  serializer: (value) => JSON.stringify(value),
});
Type Declarations
export type CookieParams = Record<string, any>;
export interface UseCookiesOptions<Value> {
  deserializer?: (value: string) => Value[keyof Value];
  serializer?: (value: Value[keyof Value]) => string;
}
export declare const useCookies: <Value extends CookieParams>(
  options?: UseCookiesOptions<Value>
) => {
  value: Value;
  set: <Key extends keyof Value>(
    key: Key,
    value: Value[Key],
    options?: SetCookieParams
  ) => void;
  remove: <Key extends keyof Value>(
    key: Key,
    options?: RemoveCookieParams
  ) => void;
  getAll: () => Value;
  clear: () => void;
};

7.5 useCounter

Manages a numeric counter with bounds.

Usage
import { useCounter } from "@siberiacancode/reactuse";

const counter = useCounter(0);
Example
const counter = useCounter(0);

return (
  <div>
    <button onClick={() => counter.dec()}>-</button>
    <span>{counter.value}</span>
    <button onClick={() => counter.inc()}>+</button>
  </div>
);

initialValue:

const counter = useCounter(5);

min:

const counter = useCounter({ initialValue: 0, min: 0 });

max:

const counter = useCounter({ initialValue: 0, max: 10 });
Type Declarations
import type { Dispatch, SetStateAction } from "react";

export interface UseCounterOptions {
  max?: number;
  min?: number;
}
export interface UseCounterReturn {
  set: Dispatch<SetStateAction<number>>;
  value: number;
  dec: (value?: number) => void;
  inc: (value?: number) => void;
  reset: () => void;
}
export interface UseCounter {
  (initialValue?: number, options?: UseCounterOptions): UseCounterReturn;
  (
    options: UseCounterOptions & { initialValue?: number },
    initialValue?: never
  ): UseCounterReturn;
}
export declare const useCounter: UseCounter;

7.6 useCycleList

Models a finite set of ordered choices as a current value plus helpers for moving through the list.

Usage
import { useCycleList } from "@siberiacancode/reactuse";

const cycle = useCycleList(["light", "dark", "system"]);
Example
import { useCycleList } from "@siberiacancode/reactuse";

export const ThemeCycle = () => {
  const { value, next, prev } = useCycleList(["light", "dark", "system"]);

  return (
    <div>
      <button onClick={() => prev()}>Prev</button>
      <span>{value}</span>
      <button onClick={() => next()}>Next</button>
    </div>
  );
};

list:

const cycle = useCycleList(["light", "dark", "system"]);

initialIndex:

const cycle = useCycleList(["small", "medium", "large"], 1);

next(step):

cycle.next(2);

prev(step):

cycle.prev();

go(index):

cycle.go(0);
Type Declarations
export interface UseCycleListReturn<Value> {
  index: number;
  value: Value;
  go: (index: number) => Value;
  next: (step?: number) => Value;
  prev: (step?: number) => Value;
}
export declare const useCycleList: <Value>(
  list: Value[],
  initialIndex?: number,
) => UseCycleListReturn<Value>;

7.7 useDefault

Returns a value or a provided default when nullish.

Usage
import { useDefault } from "@siberiacancode/reactuse";

const [value, setValue] = useDefault("initial", "fallback");
Example
import { useDefault } from "@siberiacancode/reactuse";

interface TitleProps {
  value: string;
}

export const Title = ({ value }: TitleProps) => {
  const [text] = useDefault(value, "Untitled");
  return <span>{text}</span>;
};

initialValue:

const [value, setValue] = useDefault("value", "fallback");

defaultValue:

const [value, setValue] = useDefault(undefined, "fallback");
Type Declarations
export declare const useDefault: <Value>(
  initialValue: (() => Value) | Value,
  defaultValue: Value
) => readonly [Value, (value: Value) => void];

7.8 useDisclosure

Manages open/close state with helpers.

Usage
import { useDisclosure } from "@siberiacancode/reactuse";

const disclosure = useDisclosure();
Example
import { useDisclosure } from "@siberiacancode/reactuse";

export const Modal = () => {
  const disclosure = useDisclosure();

  return (
    <div>
      <button onClick={() => disclosure.open()}>Open</button>
      {disclosure.opened && <div>Modal content</div>}
    </div>
  );
};

initialValue:

const disclosure = useDisclosure(true);

onOpen:

const disclosure = useDisclosure(false, { onOpen: () => console.log("open") });

onClose:

const disclosure = useDisclosure(false, {
  onClose: () => console.log("close"),
});
Type Declarations
export interface UseDisclosureOptions {
  onClose?: () => void;
  onOpen?: () => void;
}
export interface UseDisclosureReturn {
  opened: boolean;
  close: () => void;
  open: () => void;
  toggle: (value?: boolean) => void;
}
export declare const useDisclosure: (
  initialValue?: boolean,
  options?: UseDisclosureOptions
) => UseDisclosureReturn;

7.9 useField

Keeps a single uncontrolled form control connected to React state for validation, touched/dirty flags, and imperative field helpers.

Usage
import { useField } from "@siberiacancode/reactuse";

const field = useField();
// or with initial value and options
const field = useField("", { validateOnBlur: true });
Example
import { useField } from "@siberiacancode/reactuse";

export const EmailField = () => {
  const field = useField("", { validateOnBlur: true });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        console.log(field.getValue());
      }}
    >
      <input
        {...field.register({
          required: "Required",
          onBlur: () => console.log("blur"),
        })}
      />
      {field.error && <span>{field.error}</span>}
      <button type="submit">Submit</button>
    </form>
  );
};

initialValue:

const field = useField();
const fieldNum = useField(0);
const fieldChecked = useField(false);

initialTouched:

const field = useField("", { initialTouched: true });

autoFocus:

const field = useField("", { autoFocus: true });

validateOnChange:

const field = useField("", { validateOnChange: true });

validateOnBlur:

const email = useField("", {
  validateOnBlur: true,
  required: "Email is required",
});

validateOnMount:

const field = useField("", { validateOnMount: true });

register.onChange:

const field = useField("");
return (
  <input
    {...field.register({
      onChange: (event) => console.log(event.currentTarget.value),
    })}
  />
);

register.onBlur:

const field = useField("");
return <input {...field.register({ onBlur: () => console.log("blur") })} />;

register.required:

const field = useField("");
return <input {...field.register({ required: "Required" })} />;

register.validate:

const field = useField("");
return <input {...field.register({ validate: (value) => value ? true : "Empty" })} />;

register.max:

const age = useField(0);
return <input type="number" {...age.register({ max: { value: 99, message: "Too old" } })} />;

register.maxLength:

const field = useField("");
return <input {...field.register({ maxLength: { value: 20, message: "Too long" } })} />;

register.min:

const age = useField(0);
return <input type="number" {...age.register({ min: { value: 18, message: "Too young" } })} />;

register.minLength:

const field = useField();
return (
  <input
    {...field.register({
      required: "Required",
      minLength: { value: 3, message: "Too short" },
    })}
  />
);

register.pattern:

const email = useField("");
return <input {...email.register({ pattern: { value: /\S+@\S+\.\S+/, message: "Invalid" } })} />;
Notes
  • By default the hook does not re-render on every input value change. To render the current value in JSX, subscribe via watch(): call it once per render, for example const value = field.watch(), then the component will re-render when the field changes. Use getValue() for one-off reads such as submit handlers.
Type Declarations
import type {
  ChangeEventHandler,
  FocusEventHandler,
  RefObject,
} from "react";

type UseFieldElement =
  | HTMLInputElement
  | HTMLSelectElement
  | HTMLTextAreaElement;

export interface UseFieldRegisterParams {
  max?: { value: number; message: string };
  maxLength?: { value: number; message: string };
  min?: { value: number; message: string };
  minLength?: { value: number; message: string };
  onBlur?: FocusEventHandler<UseFieldElement>;
  onChange?: ChangeEventHandler<UseFieldElement>;
  pattern?: { value: RegExp; message: string };
  required?: string;
  validate?: (value: string) => string | true | Promise<string | true>;
}
export interface UseFieldOptions extends UseFieldRegisterParams {
  autoFocus?: boolean;
  initialTouched?: boolean;
  validateOnBlur?: boolean;
  validateOnChange?: boolean;
  validateOnMount?: boolean;
}
export interface UseFieldReturn<Value> {
  dirty: boolean;
  error?: string;
  ref: RefObject<UseFieldElement | null>;
  touched: boolean;
  clearError: () => void;
  focus: () => void;
  getValue: () => Value;
  register: (params?: UseFieldRegisterParams) => {
    onBlur: FocusEventHandler<UseFieldElement>;
    onChange: ChangeEventHandler<UseFieldElement>;
    ref: (node: UseFieldElement | null | undefined) => void;
  };
  reset: () => void;
  setError: (error: string) => void;
  setValue: (value: Value) => void;
  watch: () => Value;
}
export declare const useField: <
  Value extends boolean | number | string | unknown = string,
  Type = Value extends string
    ? string
    : Value extends boolean
    ? boolean
    : number
>(
  initialValue?: Value,
  options?: UseFieldOptions
) => UseFieldReturn<Type>;

7.10 useForm

Coordinates uncontrolled form fields behind a typed values object so validation, errors, submit state, and imperative form helpers stay in one place.

Usage
import { useForm } from "@siberiacancode/reactuse";

const form = useForm({ initialValues: { email: "" } });
Example
import { useForm } from "@siberiacancode/reactuse";

export const LoginForm = () => {
  const form = useForm({
    initialValues: { email: "", password: "" },
    validateOnBlur: true,
  });

  return (
    <form onSubmit={form.handleSubmit((values) => console.log(values))}>
      <input {...form.register("email", { required: "Email is required" })} />
      {form.errors.email && <span>{form.errors.email}</span>}
      <input
        type="password"
        {...form.register("password", { minLength: { value: 6, message: "Too short" } })}
      />
      <button disabled={form.submitting}>Submit</button>
    </form>
  );
};

resolver:

const form = useForm({
  initialValues: { email: "" },
  resolver: (values) => ({
    values,
    errors: values.email.includes("@") ? {} : { email: "Invalid email" },
  }),
});

autoFocus:

const form = useForm({ initialValues: { email: "" }, autoFocus: "email" });

initialValues:

const form = useForm({ initialValues: { email: "", remember: false } });

validateOnBlur:

const form = useForm({ initialValues: { email: "" }, validateOnBlur: true });

validateOnChange:

const form = useForm({ initialValues: { email: "" }, validateOnChange: true });

validateOnMount:

const form = useForm({ initialValues: { email: "" }, validateOnMount: true });

register.required:

<input {...form.register("email", { required: "Email is required" })} />;

register.validate:

<input {...form.register("email", { validate: (value) => value ? true : "Empty" })} />;

register.max:

<input type="number" {...form.register("age", { max: { value: 99, message: "Too old" } })} />;

register.maxLength:

<input {...form.register("name", { maxLength: { value: 40, message: "Too long" } })} />;

register.min:

<input type="number" {...form.register("age", { min: { value: 18, message: "Too young" } })} />;

register.minLength:

<input {...form.register("password", { minLength: { value: 6, message: "Too short" } })} />;

register.pattern:

<input {...form.register("email", { pattern: { value: /\S+@\S+\.\S+/, message: "Invalid" } })} />;

register.onChange:

<input {...form.register("email", { onChange: (event) => console.log(event.currentTarget.value) })} />;

register.onBlur:

<input {...form.register("email", { onBlur: () => console.log("blur") })} />;
Notes
  • By default the hook keeps field values in refs and does not re-render on every input value change. To render live form values in JSX, subscribe via watch(): call it once per render, for example const values = form.watch(), then the component will re-render when registered fields change. Use getValues() for one-off reads.
Type Declarations
import type { BaseSyntheticEvent, ChangeEventHandler, FocusEventHandler } from "react";

type UseFormElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
export type UseFormErrors<Values> = Partial<Record<keyof Values, string>>;
export interface UseFormResolverResult<Values> {
  errors: UseFormErrors<Values>;
  values: Values;
}
export type UseFormResolver<Values> = (
  values: Values
) => Promise<UseFormResolverResult<Values>> | UseFormResolverResult<Values>;
export interface UseFormOptions<Values> {
  autoFocus?: keyof Values;
  initialValues: Values;
  resolver?: UseFormResolver<Values>;
  validateOnBlur?: boolean;
  validateOnChange?: boolean;
  validateOnMount?: boolean;
}
export interface UseFormRegisterParams<Values = any> {
  max?: { value: number; message: string };
  maxLength?: { value: number; message: string };
  min?: { value: number; message: string };
  minLength?: { value: number; message: string };
  onBlur?: FocusEventHandler<UseFormElement>;
  onChange?: ChangeEventHandler<UseFormElement>;
  pattern?: { value: RegExp; message: string };
  required?: string;
  validate?: (value: any, values: Values) => string | true | Promise<string | true>;
}
export interface UseFormReturn<Values extends Record<string, any>> {
  dirty: Partial<Record<keyof Values, boolean>>;
  errors: UseFormErrors<Values>;
  submitting: boolean;
  touched: Partial<Record<keyof Values, boolean>>;
  clearErrors: (name?: keyof Values) => void;
  focus: (name: keyof Values) => void;
  getValue: <Name extends keyof Values>(name: Name) => Values[Name];
  getValues: () => Values;
  handleSubmit: (
    onValid: (values: Values, event?: BaseSyntheticEvent) => any,
    onInvalid?: (errors: UseFormErrors<Values>, event?: BaseSyntheticEvent) => any
  ) => (event?: BaseSyntheticEvent) => Promise<void>;
  register: (name: keyof Values, params?: UseFormRegisterParams<Values>) => {
    name: string;
    onBlur: FocusEventHandler<UseFormElement>;
    onChange: ChangeEventHandler<UseFormElement>;
    ref: (node: UseFormElement | null | undefined) => void;
  };
  reset: (values?: Partial<Values>) => void;
  setError: (name: keyof Values, error: string) => void;
  setValue: <Name extends keyof Values>(name: Name, value: Values[Name]) => void;
  trigger: (name?: (keyof Values)[] | keyof Values, options?: { shouldFocus?: boolean }) => Promise<boolean>;
  watch: () => Values;
}
export declare const useForm: <Values extends Record<string, any>>(
  options: UseFormOptions<Values>
) => UseFormReturn<Values>;

7.11 useHash

Manages URL hash value.

Usage
import { useHash } from "@siberiacancode/reactuse";

const hash = useHash("section");
Example

initialValue:

Initial hash value.

const hash = useHash("intro");

enabled:

Enables or disables hash tracking and updates.

const hash = useHash({ enabled: false });

mode:

Controls how the hash is written ("initial" preserves existing hash, "replace" updates it).

const hash = useHash({ mode: "initial" });

onChange:

Called when the hash changes.

const hash = useHash({ onChange: (value) => console.log(value) });
Type Declarations
export interface UseHashOptions {
  enabled?: boolean;
  mode?: "initial" | "replace";
  onChange?: (hash: string) => void;
}
type UseHashReturn = [string, (value: string) => void];
export interface UseHash {
  (initialValue?: string, options?: UseHashOptions): UseHashReturn;
  (options?: UseHashOptions): UseHashReturn;
  (initialValue?: string, callback?: (hash: string) => void): UseHashReturn;
  (callback?: (hash: string) => void): UseHashReturn;
}
export declare const useHash: UseHash;

7.12 useList

Manages an array with helper methods.

Usage
import { useList } from "@siberiacancode/reactuse";

const list = useList(["a", "b"]);
Example
import { useList } from "@siberiacancode/reactuse";

export const TodoList = () => {
  const list = useList(["a", "b"]);

  return (
    <div>
      <button onClick={() => list.push("c")}>Add</button>
      <div>{list.value.join(", ")}</div>
    </div>
  );
};

initialList:

const list = useList([1, 2, 3]);
Type Declarations
export interface UseListReturn<Item> {
  value: Item[];
  clear: () => void;
  insertAt: (insertAtIndex: number, item: Item) => void;
  push: (item: Item) => void;
  removeAt: (removeAtIndex: number) => void;
  set: (list: Item[]) => void;
  updateAt: (updateAtIndex: number, item: Item) => void;
}
export declare const useList: <Item>(initialList?: Item[]) => {
  value: Item[];
  set: (list: Item[]) => void;
  push: (item: Item) => void;
  removeAt: (removeAtIndex: number) => void;
  insertAt: (insertAtIndex: number, item: Item) => void;
  updateAt: (updateAtIndex: number, item: Item) => void;
  clear: () => void;
  reset: () => void;
};

7.13 useLocalStorage

Manages a value in localStorage.

Usage
import { useLocalStorage } from "@siberiacancode/reactuse";

const storage = useLocalStorage("key", "value");
Example
import { useLocalStorage } from "@siberiacancode/reactuse";

export const DraftNote = () => {
  const draft = useLocalStorage("draft-note", "");

  return (
    <textarea
      value={draft.value}
      onChange={(event) => draft.set(event.target.value)}
      placeholder="Type your note..."
    />
  );
};

initialValue:

const storage = useLocalStorage("key", "value");
storage.set("next");

deserializer:

const storage = useLocalStorage(
  "settings",
  { compact: false },
  {
    deserializer: (value) => JSON.parse(value) as { compact: boolean },
  }
);
storage.set({ compact: true });

serializer:

const storage = useLocalStorage(
  "filters",
  { query: "" },
  {
    serializer: (value) => JSON.stringify(value),
  }
);
storage.set({ query: "react" });
Notes
Type Declarations
import type {
  UseStorageInitialValue,
  UseStorageOptions,
} from "@siberiacancode/reactuse";

export declare const useLocalStorage: <Value>(
  key: string,
  initialValue?: UseStorageInitialValue<Value>,
  options?: Omit<UseStorageOptions<Value>, "initialValue" | "storage">
) => {
  value: Value;
  set: (value: Value) => void;
  remove: () => void;
};

7.14 useMap

Manages a Map with helper methods.

Usage
import { useMap } from "@siberiacancode/reactuse";

const map = useMap([["id", 1]]);
Example
import { useMap } from "@siberiacancode/reactuse";

export const Lookup = () => {
  const map = useMap([["a", 1]]);

  return <button onClick={() => map.set("b", 2)}>Size: {map.size}</button>;
};
Type Declarations
export interface UseMapReturn<Key, Value> {
  size: number;
  value: Map<Key, Value>;
  clear: () => void;
  has: (key: Key) => boolean;
  remove: (key: Key) => void;
  reset: () => void;
  set: (key: Key, value: Value) => void;
}
export declare const useMap: <Key, Value>(
  values?: [Key, Value][]
) => UseMapReturn<Key, Value>;

7.15 useMask

Keeps the DOM input value, raw value, display mask, cursor behavior, and validation callbacks aligned for masked text fields.

Usage
import { useMask } from "@siberiacancode/reactuse";

const phone = useMask("+9 (999) 999-99-99");
Example
import { useMask } from "@siberiacancode/reactuse";

export const PhoneField = () => {
  const phone = useMask("+9 (999) 999-99-99", {
    showMask: "focus",
  });

  return (
    <label>
      Phone
      <input {...phone.register()} />
      <span>{phone.watch().rawValue}</span>
    </label>
  );
};

tokens:

const serial = useMask("AA-999", { tokens: { A: /[A-Z]/ } });

autoClear:

const phone = useMask("+9 (999) 999-99-99", { autoClear: true });

beforeMaskedChange:

const phone = useMask("+9 (999) 999-99-99", {
  beforeMaskedChange: ({ nextState }) => nextState,
});

initialValue:

const phone = useMask("+9 (999) 999-99-99", { initialValue: "79990000000" });

mask as array:

const code = useMask(["#", /\d/, /\d/, "-", /\d/]);

modify:

const card = useMask("9999 9999 9999 9999", {
  modify: (value) => (value.startsWith("34") ? { mask: "9999 999999 99999" } : {}),
});

onChangeRaw:

const phone = useMask("+9 (999) 999-99-99", {
  onChangeRaw: (rawValue) => console.log(rawValue),
});

onFilled:

const phone = useMask("+9 (999) 999-99-99", {
  onFilled: (maskedValue) => console.log(maskedValue),
});

showMask:

const phone = useMask("+9 (999) 999-99-99", { showMask: "focus" });

slot:

const date = useMask("99/99/9999", { slot: "_" });

transform:

const serial = useMask("AA-999", {
  transform: (char) => char.toUpperCase(),
});

register(params):

<input {...phone.register({ onBlur: () => console.log(phone.getValue()) })} />;

getValue(type):

const raw = phone.getValue();
const masked = phone.getValue("masked");
const display = phone.getValue("display");

sanitize(value, options):

import { sanitize } from "@siberiacancode/reactuse";

const raw = sanitize("+7 (999) 123-45-67", {
  mask: "+9 (999) 999-99-99",
});
Notes
  • Default tokens: 9 digit, a letter, A uppercase letter, * alphanumeric, # signed digit.
  • By default the hook stores the input value in refs and does not re-render on every edit. To render live masked state in JSX, subscribe via watch(): call it once per render, for example const value = mask.watch(), then the component will re-render when the masked value changes. Use getValue() for one-off reads.
Type Declarations
import type {
  ChangeEventHandler,
  ClipboardEventHandler,
  FocusEventHandler,
  KeyboardEventHandler,
  MouseEventHandler,
  RefObject,
} from "react";

export type UseMaskPattern = string | Array<string | RegExp>;
export type UseMaskShow = "always" | "filled" | "focus" | "never";
export type UseMaskGetValueType = "display" | "masked" | "raw";
export interface UseMaskOptions {
  autoClear?: boolean;
  initialValue?: string;
  mask: UseMaskPattern;
  showMask?: UseMaskShow;
  slot?: string;
  tokens?: Record<string, RegExp>;
  beforeMaskedChange?: (states: {
    previousState: MaskState;
    currentState: MaskState;
    nextState: MaskState;
  }) => MaskState;
  modify?: (
    value: string
  ) => Partial<Pick<UseMaskOptions, "mask" | "showMask" | "slot" | "tokens">>;
  onChangeRaw?: (rawValue: string, maskedValue: string) => void;
  onFilled?: (maskedValue: string, rawValue: string) => void;
  transform?: (char: string) => string;
}
export interface MaskState {
  selection: { start: number; end: number } | null;
  value: string;
}
export interface UseMaskRegisterParams {
  onBlur?: FocusEventHandler<HTMLInputElement>;
  onChange?: ChangeEventHandler<HTMLInputElement>;
  onFocus?: FocusEventHandler<HTMLInputElement>;
  onKeyDown?: KeyboardEventHandler<HTMLInputElement>;
  onMouseDown?: MouseEventHandler<HTMLInputElement>;
  onMouseUp?: MouseEventHandler<HTMLInputElement>;
  onPaste?: ClipboardEventHandler<HTMLInputElement>;
}
export interface UseMaskGetValueMap {
  display: string;
  masked: string;
  raw: string;
}
export interface UseMaskValue {
  displayValue: string;
  filled: boolean;
  maskedValue: string;
  rawValue: string;
  value: string;
}
export interface UseMaskReturn {
  ref: RefObject<HTMLInputElement | null>;
  getValue: <Type extends UseMaskGetValueType = "raw">(type?: Type) => UseMaskGetValueMap[Type];
  register: (params?: UseMaskRegisterParams) => {
    onBlur?: FocusEventHandler<HTMLInputElement>;
    onChange?: ChangeEventHandler<HTMLInputElement>;
    onFocus?: FocusEventHandler<HTMLInputElement>;
    onKeyDown?: KeyboardEventHandler<HTMLInputElement>;
    onMouseDown?: MouseEventHandler<HTMLInputElement>;
    onMouseUp?: MouseEventHandler<HTMLInputElement>;
    onPaste?: ClipboardEventHandler<HTMLInputElement>;
    ref: (node: HTMLInputElement | null | undefined) => void;
  };
  reset: () => void;
  setValue: (value: string) => void;
  watch: () => UseMaskValue;
}
export type UseMaskReturnValue = UseMaskReturn;
export declare const sanitize: (value: string, options: UseMaskOptions) => string;
export declare const formatMask: (rawValue: string, options: UseMaskOptions) => string;
export declare const unformatMask: (maskedValue: string, options: UseMaskOptions) => string;
export declare const isMaskComplete: (maskedValue: string, options: UseMaskOptions) => boolean;
export declare const generatePattern: (
  mode: "full-inexact" | "full",
  options: UseMaskOptions
) => string;
export declare const useMask: (
  mask: UseMaskPattern,
  options?: Omit<UseMaskOptions, "mask">
) => UseMaskReturn;

7.16 useMergedRef

Merges multiple refs into a single ref callback.

Usage
import { useMergedRef } from "@siberiacancode/reactuse";

const ref = useMergedRef(firstRef, secondRef);
Example
import { useMergedRef } from "@siberiacancode/reactuse";
import { useRef } from "react";
import type { RefObject } from "react";

interface FocusInputProps {
  inputRef: RefObject<HTMLInputElement>;
}

export const FocusInput = ({ inputRef }: FocusInputProps) => {
  const localRef = useRef<HTMLInputElement | null>(null);
  const merged = useMergedRef(inputRef, localRef);

  return <input ref={merged} />;
};
Type Declarations
import type { Ref, RefCallback } from "react";

export declare const useMergedRef: <Element>(
  ...refs: Ref<Element>[]
) => RefCallback<Element>;

7.17 useObject

Manages object state with helper methods for updates and key operations.

Usage
import { useObject } from "@siberiacancode/reactuse";

const user = useObject({ name: "John", age: 30, active: true });
Example
import { useObject } from "@siberiacancode/reactuse";

export const UserCard = () => {
  const user = useObject({ name: "John", age: 30, active: true });

  return (
    <div>
      <p>{user.value.name}</p>
      <p>Fields: {user.size}</p>
      <button onClick={() => user.set({ active: !user.value.active })}>
        Toggle active
      </button>
      <button onClick={() => user.remove("age")}>Remove age</button>
      <button onClick={() => user.reset()}>Reset</button>
    </div>
  );
};
Type Declarations
export interface UseObjectReturn<Value extends object> {
  empty: boolean;
  keys: Array<keyof Value>;
  size: number;
  value: Value;
  clear: () => void;
  has: (key: keyof Value) => boolean;
  remove: (key: keyof Value) => void;
  reset: () => void;
  set: (value: Partial<Value>) => void;
}
export declare function useObject<Value extends object>(
  initialValue: Value
): UseObjectReturn<Value>;

7.18 useOffsetPagination

Manages pagination state for offset-based lists.

Usage
import { useOffsetPagination } from "@siberiacancode/reactuse";

const pagination = useOffsetPagination({ total: 100, initialPageSize: 10 });
Example
import { useOffsetPagination } from "@siberiacancode/reactuse";

export const Pager = () => {
  const pagination = useOffsetPagination({ total: 200, initialPageSize: 20 });

  return (
    <div>
      Page {pagination.page} of {pagination.pageCount}
      <button onClick={() => pagination.prev()}>Prev</button>
      <button onClick={() => pagination.next()}>Next</button>
    </div>
  );
};

total:

const pagination = useOffsetPagination({ total: 200 });

initialPageSize:

const pagination = useOffsetPagination({ initialPageSize: 20 });

initialPage:

const pagination = useOffsetPagination({ initialPage: 2 });

onChange:

const pagination = useOffsetPagination({
  onChange: ({ page, pageSize }) => console.log(page, pageSize),
});
Type Declarations
export interface UseOffsetPaginationOptions {
  initialPage?: number;
  initialPageSize?: number;
  total?: number;
  onChange?: ({ page, pageSize }: { page: number; pageSize: number }) => void;
}
export interface UseOffsetPaginationReturn {
  isFirstPage: boolean;
  isLastPage: boolean;
  page: number;
  pageCount: number;
  pageSize: number;
  next: () => void;
  prev: () => void;
  setPage: (page: number) => void;
  setPageSize: (pageSize: number) => void;
}
export declare const useOffsetPagination: (
  options?: UseOffsetPaginationOptions
) => UseOffsetPaginationReturn;

7.19 useQueue

Manages a queue with add/remove helpers.

Usage
import { useQueue } from "@siberiacancode/reactuse";

const queue = useQueue([1, 2, 3]);
Example
const queue = useQueue(["a", "b"]);

return (
  <div>
    <button onClick={() => queue.add("c")}>Add</button>
    <button onClick={() => queue.remove()}>Next</button>
    <div>Size: {queue.size}</div>
  </div>
);

initialValue:

const queue = useQueue(["a", "b"]);
Type Declarations
export interface UseQueueReturn<Value> {
  first: Value;
  last: Value;
  queue: Value[];
  size: number;
  add: (element: Value) => void;
  clear: () => void;
  remove: () => Value;
}
export declare const useQueue: <Value>(
  initialValue?: Value[]
) => UseQueueReturn<Value>;

7.20 useRafState

Updates state inside requestAnimationFrame.

Usage
import { useRafState } from "@siberiacancode/reactuse";

const [value, setValue] = useRafState(0);
Example
const [value, setValue] = useRafState(0);
return <button onClick={() => setValue(value + 1)}>Value: {value}</button>;

initialValue:

const [value, setValue] = useRafState(() => 0);
Notes
Type Declarations
export type UseRafStateReturn<Value> = [Value, (value: Value) => void];
export declare const useRafState: <Value>(
  initialValue: (() => Value) | Value
) => readonly [Value, (value: Value) => void];

7.21 useRefState

Creates a ref-like state that updates on assignment.

Usage
import { useRefState } from "@siberiacancode/reactuse";

const ref = useRefState();
Example

initialValue:

const ref = useRefState(0);

return <button onClick={() => ref.current += 1;}>Increment {ref.current}</button>;
Type Declarations
export interface StateRef<Value> {
  (node: Value): void;
  current: Value;
  state?: Value;
}
export declare const useRefState: <Value>(
  initialValue?: Value
) => StateRef<Value>;

7.22 useSessionStorage

Manages a value in sessionStorage.

Usage
import { useSessionStorage } from "@siberiacancode/reactuse";

const storage = useSessionStorage("key", "value");
Example
import { useSessionStorage } from "@siberiacancode/reactuse";

export const CheckoutStep = () => {
  const step = useSessionStorage("checkout-step", 1);

  return (
    <button onClick={() => step.set(step.value + 1)}>Step {step.value}</button>
  );
};

initialValue:

const storage = useSessionStorage("key", "value");
storage.set("next");

deserializer:

const storage = useSessionStorage(
  "user",
  { name: "" },
  {
    deserializer: (value) => JSON.parse(value) as { name: string },
  }
);
storage.set({ name: "Ada" });

serializer:

const storage = useSessionStorage(
  "filters",
  { query: "" },
  {
    serializer: (value) => JSON.stringify(value),
  }
);
storage.set({ query: "design" });
Notes
Type Declarations
import type {
  UseStorageInitialValue,
  UseStorageOptions,
} from "@siberiacancode/reactuse";

export declare const useSessionStorage: <Value>(
  key: string,
  initialValue?: UseStorageInitialValue<Value>,
  options?: Omit<UseStorageOptions<Value>, "initialValue" | "storage">
) => {
  value: Value;
  set: (value: Value) => void;
  remove: () => void;
};

7.23 useSet

Manages a Set with helper methods.

Usage
import { useSet } from "@siberiacancode/reactuse";

const set = useSet([1, 2, 3]);
Example
const set = useSet(["a"]);
return <button onClick={() => set.toggle("b")}>Size: {set.size}</button>;

values:

const set = useSet(["a", "b"]);
Type Declarations
interface UseSetReturn<Value> {
  size: number;
  value: Set<Value>;
  add: (value: Value) => void;
  clear: () => void;
  difference: (other: Set<Value>) => void;
  has: (value: Value) => boolean;
  intersection: (other: Set<Value>) => void;
  remove: (value: Value) => void;
  reset: () => void;
  symmetricDifference: (other: Set<Value>) => void;
  toggle: (value: Value) => void;
  union: (other: Set<Value>) => void;
}
export declare const useSet: <Value>(values?: Value[]) => UseSetReturn<Value>;

7.24 useStateHistory

Keeps state with undo/redo history.

Usage
import { useStateHistory } from "@siberiacancode/reactuse";

const history = useStateHistory(0);
Example
import { useStateHistory } from "@siberiacancode/reactuse";

export const HistoryInput = () => {
  const history = useStateHistory("draft");

  return (
    <div>
      <button onClick={() => history.undo()}>Undo</button>
      <button onClick={() => history.redo()}>Redo</button>
      <div>Value: {history.value}</div>
    </div>
  );
};

initialValue:

const history = useStateHistory("draft");

capacity:

const history = useStateHistory(0, 50);
Type Declarations
interface UseStateHistoryReturn<Value> {
  canRedo: boolean;
  canUndo: boolean;
  history: Value[];
  index: number;
  value: Value;
  back: (steps?: number) => void;
  forward: (steps?: number) => void;
  redo: () => void;
  reset: () => void;
  set: (value: Value) => void;
  undo: () => void;
}
export declare const useStateHistory: <Value>(
  initialValue: Value,
  capacity?: number
) => UseStateHistoryReturn<Value>;

7.25 useStep

Creates a stepper with next/back helpers.

Usage
import { useStep } from "@siberiacancode/reactuse";

const stepper = useStep(5);
Example
import { useStep } from "@siberiacancode/reactuse";

export const Stepper = () => {
  const stepper = useStep({ initial: 1, max: 3 });

  return (
    <div>
      Step {stepper.currentStep} / {stepper.counts}
      <button onClick={() => stepper.back()}>Back</button>
      <button onClick={() => stepper.next()}>Next</button>
    </div>
  );
};

max:

const stepper = useStep(10);

initial:

const stepper = useStep({ initial: 2, max: 5 });
Type Declarations
export interface UseStepParams {
  initial: number;
  max: number;
}
export interface UseStepReturn {
  counts: number;
  currentStep: number;
  isFirst: boolean;
  isLast: boolean;
  back: () => void;
  next: () => void;
  reset: () => void;
  set: (value: number | "first" | "last") => void;
}
export declare const useStep: (params: number | UseStepParams) => UseStepReturn;

7.26 useStorage

Manages a value in Web Storage.

Usage
import { useStorage } from "@siberiacancode/reactuse";

const storage = useStorage("key", "value");
Example
import { useStorage } from "@siberiacancode/reactuse";

export const Preferences = () => {
  const prefs = useStorage("prefs", { theme: "light", density: "comfortable" });

  return (
    <button onClick={() => prefs.set({ ...prefs.value, theme: "dark" })}>
      Theme: {prefs.value.theme}
    </button>
  );
};

initialValue:

const storage = useStorage("key", { initialValue: "value" });
storage.set("next");

storage:

const storage = useStorage("wizard-step", { storage: sessionStorage });
storage.set(2);

deserializer:

const storage = useStorage("settings", {
  deserializer: (value) => JSON.parse(value) as { compact: boolean },
});
storage.set({ compact: true });

serializer:

const storage = useStorage("filters", {
  serializer: (value) => JSON.stringify(value),
});
storage.set({ query: "react" });
Type Declarations
export type UseStorageInitialValue<Value> = (() => Value) | Value;
export interface UseStorageOptions<Value> {
  initialValue?: UseStorageInitialValue<Value>;
  storage?: Storage;
  deserializer?: (value: string) => Value;
  serializer?: (value: Value) => string;
}
export interface UseStorageReturn<Value> {
  value: Value;
  remove: () => void;
  set: (value: Value) => void;
}
export interface UseStorage {
  <Value>(key: string, options?: UseStorageOptions<Value>): UseStorageReturn<
    Value | undefined
  >;
  <Value>(
    key: string,
    initialValue?: UseStorageInitialValue<Value>
  ): UseStorageReturn<Value | undefined>;
}
export declare const useStorage: UseStorage;

7.27 useToggle

A boolean switcher with utility functions.

Usage
import { useToggle } from "@siberiacancode/reactuse";

const [on, toggle] = useToggle();
// or
const [value, toggle] = useToggle(["light", "dark"] as const);
import { useToggle } from "@siberiacancode/reactuse";

export const Toggle = () => {
  const [value, toggle] = useToggle();

  return <button onClick={() => toggle()}>{String(value)}</button>;
};

Example in a component with array toggle:

import { useToggle } from "@siberiacancode/reactuse";

export const UserTypeToggle = () => {
  const [type, toggle] = useToggle(["user", "admin"] as const);

  return <button onClick={() => toggle()}>Current: {userType}</button>;
};
Type Declarations
export type ToggleFn = (value?: boolean) => void;
export type UseToggleReturn = [boolean, ToggleFn];
export declare const useToggle: (initialValue?: boolean): UseToggleReturn;

7.28 useUrlSearchParam

Syncs a single URL search param with state.

Usage
import { useUrlSearchParam } from "@siberiacancode/reactuse";

const param = useUrlSearchParam("page", { initialValue: 1 });
Example
import { useUrlSearchParam } from "@siberiacancode/reactuse";

export const PageParam = () => {
  const param = useUrlSearchParam("page", { initialValue: 1 });

  return (
    <button onClick={() => param.set((param.value ?? 1) + 1)}>
      Page {param.value ?? 1}
    </button>
  );
};

initialValue:

const param = useUrlSearchParam("page", { initialValue: 1 });

If the URL does not already contain the key, initialValue is returned immediately and written to the URL after mount.

mode:

const param = useUrlSearchParam("page", { mode: "hash" });

write:

const param = useUrlSearchParam("page", { write: "push" });

deserializer:

const param = useUrlSearchParam("page", {
  deserializer: (value) => Number(value),
});

serializer:

const param = useUrlSearchParam("page", {
  serializer: (value) => String(value),
});
Type Declarations
export type UrlSearchParamMode = "hash-params" | "hash" | "history";
export interface UseUrlSearchParamOptions<Value> {
  initialValue?: Value;
  mode?: UrlSearchParamMode;
  write?: "push" | "replace";
  deserializer?: (value: string) => Value;
  serializer?: (value: Value) => string;
}
export interface UseUrlSearchParamsActionOptions {
  write?: "push" | "replace";
}
export interface UseUrlSearchParamReturn<Value> {
  value: Value | undefined;
  remove: (options?: UseUrlSearchParamsActionOptions) => void;
  set: (value: Value, options?: UseUrlSearchParamsActionOptions) => void;
}
export interface UseUrlSearchParam {
  <Value>(
    key: string,
    options: UseUrlSearchParamOptions<Value> & { initialValue: Value }
  ): UseUrlSearchParamReturn<Value>;
  <Value>(
    key: string,
    options?: UseUrlSearchParamOptions<Value>
  ): UseUrlSearchParamReturn<Value | undefined>;
  <Value>(key: string, initialValue: Value): UseUrlSearchParamReturn<Value>;
  <Value>(key: string): UseUrlSearchParamReturn<Value | undefined>;
}
export declare const useUrlSearchParam: UseUrlSearchParam;

7.29 useUrlSearchParams

Syncs multiple URL search params with state.

Usage
import { useUrlSearchParams } from "@siberiacancode/reactuse";

const params = useUrlSearchParams({ initialValue: { page: 1 } });
Example
import { useUrlSearchParams } from "@siberiacancode/reactuse";

export const SearchFilters = () => {
  const params = useUrlSearchParams({
    initialValue: { page: 1, q: "" },
  });

  return (
    <button onClick={() => params.set({ page: params.value.page + 1 })}>
      Page {params.value.page}
    </button>
  );
};

initialValue:

const params = useUrlSearchParams({ initialValue: { page: 1, q: "" } });
params.set({ q: "react" });

Initial values are merged with the current URL values. Missing initial keys are written to the URL after mount, while existing URL values win.

mode:

const params = useUrlSearchParams({
  mode: "hash",
  initialValue: { tab: "all" },
});
params.set({ tab: "open" });

write:

const params = useUrlSearchParams({
  write: "push",
  initialValue: { page: 1 },
});
params.set({ page: 2 });

deserializer:

const params = useUrlSearchParams({
  deserializer: (value) => JSON.parse(value) as number,
  initialValue: { page: 1 },
});
params.set({ page: 3 });

serializer:

const params = useUrlSearchParams({
  serializer: (value) => JSON.stringify(value),
  initialValue: { page: 1 },
});
params.set({ page: 4 });

set.write:

const params = useUrlSearchParams({ initialValue: { page: 1 } });
params.set({ page: 2 }, { write: "replace" });
Type Declarations
export type UrlParams = Record<string, any>;
export type UrlSearchParamsMode = "hash-params" | "hash" | "history";
export interface UseUrlSearchParamsSetOptions {
  write?: "push" | "replace";
}
export type UseUrlSearchParamsInitialValue<Value> = (() => Value) | Value;
export interface UseUrlSearchParamsOptions<Value> {
  mode?: UrlSearchParamsMode;
  write?: "push" | "replace";
  deserializer?: (value: string) => Value[keyof Value];
  serializer?: (value: Value[keyof Value]) => string;
}
export interface UseUrlSearchParamsReturn<Value> {
  value: Value;
  set: (value: Partial<Value>, options?: UseUrlSearchParamsSetOptions) => void;
}
export interface UseUrlSearchParams {
  <Value>(
    options: UseUrlSearchParamsOptions<Value> & {
      initialValue: UseUrlSearchParamsInitialValue<Value>;
    }
  ): UseUrlSearchParamsReturn<Value>;
  <Value>(options?: UseUrlSearchParamsOptions<Value>): UseUrlSearchParamsReturn<
    Value | undefined
  >;
  <Value>(
    initialValue: UseUrlSearchParamsInitialValue<Value>
  ): UseUrlSearchParamsReturn<Value>;
}
export declare const useUrlSearchParams: UseUrlSearchParams;

7.30 useValidatedState

Keeps a value, its current validity, and the last valid value together when invalid input should remain visible.

Usage
import { useValidatedState } from "@siberiacancode/reactuse";

const [{ value, valid }, setValue] = useValidatedState("", (value) => value.length >= 3);
Example
import { useValidatedState } from "@siberiacancode/reactuse";

export const UsernameField = () => {
  const [username, setUsername] = useValidatedState(
    "",
    (value) => value.length >= 3
  );

  return (
    <label>
      Username
      <input value={username.value} onChange={(event) => setUsername(event.target.value)} />
      {!username.valid && <span>Use at least 3 characters</span>}
    </label>
  );
};

initialValue:

const [age, setAge] = useValidatedState(18, (value) => value >= 18);

validate:

const [username, setUsername] = useValidatedState("", (value) => value.length >= 3);

initialValidationState:

const [email, setEmail] = useValidatedState("", isEmail, false);
Type Declarations
export interface UseValidatedStateValue<Value> {
  lastValidValue?: Value;
  valid: boolean;
  value: Value;
}
export type UseValidatedStateReturn<Value> = [
  state: UseValidatedStateValue<Value>,
  setValue: (value: Value) => void
];
export declare const useValidatedState: <Value>(
  initialValue: Value,
  validate: (value: Value) => boolean,
  initialValidationState?: boolean
) => UseValidatedStateReturn<Value>;

7.31 useWizard

Manages wizard steps and history.

Usage
import { useWizard } from "@siberiacancode/reactuse";

const wizard = useWizard([
  { id: "step1", nodes: ["step2"] },
  { id: "step2", nodes: [] },
]);
Example
import { useWizard } from "@siberiacancode/reactuse";

export const Checkout = () => {
  const wizard = useWizard([
    { id: "shipping", nodes: ["payment"] },
    { id: "payment", nodes: ["review"] },
    { id: "review", nodes: [] },
  ]);

  return (
    <div>
      Step: {wizard.currentStepId}
      <button onClick={() => wizard.back()}>Back</button>
      <button onClick={() => wizard.set("review")}>Skip</button>
    </div>
  );
};

map:

const wizard = useWizard([
  { id: "step1", nodes: ["step2", "step3"] },
  { id: "step2", nodes: ["step3"] },
  { id: "step3", nodes: [] },
]);

initialStepId:

const wizard = useWizard(
  [
    { id: "step1", nodes: ["step2"] },
    { id: "step2", nodes: [] },
  ],
  "step2"
);
Type Declarations
export interface WizardItem<WizardStepId> {
  id: WizardStepId;
  nodes?: WizardStepId[];
}
export declare const useWizard: <WizardStepId extends string>(
  map: WizardItem<WizardStepId>[],
  initialStepId?: WizardStepId
) => {
  currentStepId: WizardStepId;
  set: (id: WizardStepId) => void;
  reset: () => void;
  back: () => void;
  history: WizardStepId[];
};

8. User

8.1 useBrowserLanguage

Returns the current browser language.

Usage
import { useBrowserLanguage } from "@siberiacancode/reactuse";

const language = useBrowserLanguage();
Example
const language = useBrowserLanguage();
return <span>Locale: {language}</span>;
Notes
Type Declarations
export declare const useBrowserLanguage: () => string;

8.2 useOperatingSystem

Returns the user's operating system based on the user agent.

Usage
import { useOperatingSystem } from "@siberiacancode/reactuse";

const os = useOperatingSystem();
Example
import { useOperatingSystem } from "@siberiacancode/reactuse";

export const OSBadge = () => {
  const os = useOperatingSystem();
  return <span>OS: {os}</span>;
};
Type Declarations
export type OperatingSystem =
  | "android"
  | "ios"
  | "linux"
  | "macos"
  | "undetermined"
  | "windows";
export declare const useOperatingSystem: () => OperatingSystem;

8.3 usePreferredColorScheme

Returns the user's preferred color scheme.

Usage
import { usePreferredColorScheme } from "@siberiacancode/reactuse";

const scheme = usePreferredColorScheme();
Example
const scheme = usePreferredColorScheme();
return <span>Scheme: {scheme}</span>;
Type Declarations
export type UsePreferredColorSchemeReturn = "dark" | "light" | "no-preference";
export declare const usePreferredColorScheme: () => UsePreferredColorSchemeReturn;

8.4 usePreferredContrast

Returns the user's contrast preference.

Usage
import { usePreferredContrast } from "@siberiacancode/reactuse";

const contrast = usePreferredContrast();
Example
import { usePreferredContrast } from "@siberiacancode/reactuse";

const contrast = usePreferredContrast();
return <span>Contrast: {contrast}</span>;
Type Declarations
export type UsePreferredContrastReturn =
  | "custom"
  | "less"
  | "more"
  | "no-preference";
export declare const usePreferredContrast: () => UsePreferredContrastReturn;

8.5 usePreferredDark

Returns whether the user prefers dark mode.

Usage
import { usePreferredDark } from "@siberiacancode/reactuse";

const isDark = usePreferredDark();
Example
const isDark = usePreferredDark();
return <div>{isDark ? "Dark mode" : "Light mode"}</div>;
Type Declarations
export declare const usePreferredDark: () => boolean;

8.6 usePreferredLanguages

Returns the user's preferred languages.

Usage
import { usePreferredLanguages } from "@siberiacancode/reactuse";

const languages = usePreferredLanguages();
Example
const languages = usePreferredLanguages();
return <div>Languages: {languages.join(", ")}</div>;
Notes
Type Declarations
export declare const usePreferredLanguages: () => readonly string[];

8.7 usePreferredReducedMotion

Returns the reduced motion preference.

Usage
import { usePreferredReducedMotion } from "@siberiacancode/reactuse";

const reduced = usePreferredReducedMotion();
Example
const reduced = usePreferredReducedMotion();
return <span>Motion: {reduced}</span>;
Type Declarations
export type UsePreferredReducedMotionReturn = "no-preference" | "reduce";
export declare const usePreferredReducedMotion: () => UsePreferredReducedMotionReturn;

9. Sensors

9.1 useDeviceMotion

Provides device motion data via snapshot and watch().

Usage
import { useDeviceMotion } from "@siberiacancode/reactuse";

const motion = useDeviceMotion();
const value = motion.watch();
Example
const motion = useDeviceMotion();
const value = motion.watch();

return (
  <div>
    {Math.round(value.accelerationIncludingGravity.x ?? 0)} /{" "}
    {Math.round(value.accelerationIncludingGravity.y ?? 0)}
  </div>
);

enabled:

const motion = useDeviceMotion({ enabled: false });

onChange:

const motion = useDeviceMotion({ onChange: (event) => console.log(event) });
Notes
  • Hook uses the DeviceMotionEvent API.
  • By default device motion updates snapshot and onChange without forcing a re-render. To render live motion data in JSX, subscribe via watch(): call it once per render, for example const value = motion.watch(), then the component will re-render on motion updates.
Type Declarations
export interface UseDeviceMotionReturn {
  snapshot: UseDeviceMotionValue;
  watch: () => UseDeviceMotionValue;
}
export interface UseDeviceMotionValue {
  acceleration: DeviceMotionEventAcceleration;
  accelerationIncludingGravity: DeviceMotionEventAcceleration;
  interval: DeviceMotionEvent["interval"];
  rotationRate: DeviceMotionEventRotationRate;
}
export interface UseDeviceMotionOptions {
  enabled?: boolean;
  onChange?: (event: DeviceMotionEvent) => void;
}
export interface UseDeviceMotion {
  (callback?: (event: DeviceMotionEvent) => void): UseDeviceMotionReturn;
  (options?: UseDeviceMotionOptions): UseDeviceMotionReturn;
}
export declare const useDeviceMotion: UseDeviceMotion;

9.2 useDeviceOrientation

Provides the current device orientation.

Usage
import { useDeviceOrientation } from "@siberiacancode/reactuse";

const orientation = useDeviceOrientation();
Example
const orientation = useDeviceOrientation();
if (!orientation.supported) return <div>Not supported</div>;

return (
  <div>
    alpha: {orientation.value.alpha ?? 0} beta: {orientation.value.beta ?? 0}
  </div>
);
Notes
Type Declarations
export interface UseDeviceOrientationValue {
  absolute: boolean;
  alpha: number | null;
  beta: number | null;
  gamma: number | null;
}
export interface UseDeviceOrientationReturn {
  supported: boolean;
  value: UseDeviceOrientationValue;
}
export declare const useDeviceOrientation: () => UseDeviceOrientationReturn;

9.3 useHotkeys

Scopes keyboard shortcuts to a target or returned ref so command-style interactions can stay close to the component that owns them.

Usage
import { useHotkeys } from "@siberiacancode/reactuse";

const ref = useHotkeys<HTMLDivElement>("ctrl+k", () => console.log("hotkey"));
// or
useHotkeys(ref, "ctrl+k", () => console.log("hotkey"));
Example
const ref = useHotkeys<HTMLDivElement>("mod+k,ctrl+/", () => {
  console.log("open command menu");
});

return <div ref={ref}>Open</div>;

enabled:

const ref = useHotkeys<HTMLDivElement>("ctrl+k", () => {}, { enabled: false });

alias:

const ref = useHotkeys<HTMLDivElement>("cmd+k", openMenu, {
  alias: { Meta: "cmd" },
});

onChange:

const ref = useHotkeys<HTMLDivElement>("escape", {
  onChange: (event) => console.log(event.key),
});

hotkeys alternatives:

const ref = useHotkeys<HTMLDivElement>("mod+k,ctrl+/", openMenu);
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export interface UseHotkeysOptions {
  alias?: Record<string, string>;
  enabled?: boolean;
  onChange?: (event: KeyboardEvent) => void;
}
export type UseHotkeysHotkeys = string;
export interface UseHotkeysKey {
  alias: string;
  code: string;
  key: string;
}
export declare const isHotkeyMatch: (
  hotkey: string,
  keys: UseHotkeysKey[]
) => boolean;
export interface UseHotkeys {
  (
    target: HookTarget,
    hotkeys: UseHotkeysHotkeys,
    options?: UseHotkeysOptions
  ): void;
  (
    target: HookTarget,
    hotkeys: UseHotkeysHotkeys,
    callback: (event: KeyboardEvent) => void,
    options?: UseHotkeysOptions
  ): void;
  <Target extends Element>(
    hotkeys: UseHotkeysHotkeys,
    options?: UseHotkeysOptions
  ): StateRef<Target>;
  <Target extends Element>(
    hotkeys: UseHotkeysHotkeys,
    callback: (event: KeyboardEvent) => void,
    options?: UseHotkeysOptions
  ): StateRef<Target>;
}
export declare const useHotkeys: UseHotkeys;

9.4 useIdle

Tracks whether the user is idle and last active time.

Usage
import { useIdle } from "@siberiacancode/reactuse";

const idle = useIdle();

callback:

const idle = useIdle(60000, (nextIdle) => console.log(nextIdle));
Example
import { useIdle } from "@siberiacancode/reactuse";

const idle = useIdle(60000);

return (
  <div>
    {idle.idle ? "Idle" : "Active"} (last: {idle.lastActive})
  </div>
);

milliseconds:

const idle = useIdle(30000);

initialValue:

const idle = useIdle(60000, { initialValue: true });

events:

const idle = useIdle(60000, { events: ["mousemove", "keydown"] });

onChange:

const idle = useIdle(60000, {
  onChange: (nextIdle) => console.log(nextIdle),
});
Type Declarations
export type UseIdleCallback = (idle: boolean) => void;
export interface UseIdleOptions {
  events?: Array<keyof DocumentEventMap>;
  initialValue?: boolean;
  onChange?: UseIdleCallback;
}
export interface UseIdleReturn {
  idle: boolean;
  lastActive: number;
}
export interface UseIdle {
  (): UseIdleReturn;
  (milliseconds: number, callback: UseIdleCallback): UseIdleReturn;
  (milliseconds: number, options?: UseIdleOptions): UseIdleReturn;
}
export declare const useIdle: UseIdle;

9.5 useInfiniteScroll

Turns proximity to a scroll edge into a guarded loading callback for paginated lists and timelines.

Usage
import { useInfiniteScroll } from "@siberiacancode/reactuse";

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(async () => {
  await loadMore();
});
// or
const infiniteScroll = useInfiniteScroll(ref, () => loadMore());
Example
import { useInfiniteScroll } from "@siberiacancode/reactuse";

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(
  () => fetchNextPage(),
  { hasMore, immediately: true }
);

return (
  <div ref={infiniteScroll.ref}>
    {items.map((item) => (
      <div key={item.id}>{item.title}</div>
    ))}
    {infiniteScroll.loading && <div>Loading...</div>}
  </div>
);

direction:

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(loadPrevious, {
  direction: "top",
});

distance:

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(loadMore, {
  distance: 50,
});

hasMore:

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(loadMore, {
  hasMore: hasNextPage,
});

immediately:

const infiniteScroll = useInfiniteScroll<HTMLDivElement>(loadMore, {
  immediately: true,
});
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export interface UseInfiniteScrollOptions {
  direction?: "bottom" | "left" | "right" | "top";
  distance?: number;
  hasMore?: boolean;
  immediately?: boolean;
}
export interface UseInfiniteScrollReturn {
  loading: boolean;
  ref: StateRef<Element>;
}
export interface UseInfiniteScroll {
  (
    target: HookTarget,
    callback: (event?: Event) => Promise<void> | void,
    options?: UseInfiniteScrollOptions
  ): UseInfiniteScrollReturn;
  <Target extends Element>(
    callback: (event?: Event) => Promise<void> | void,
    options?: UseInfiniteScrollOptions
  ): UseInfiniteScrollReturn & { ref: StateRef<Target> };
}
export declare const useInfiniteScroll: UseInfiniteScroll;

9.6 useIntersectionObserver

Tracks intersection state for an element.

Usage
import { useIntersectionObserver } from "@siberiacancode/reactuse";

const observer = useIntersectionObserver<HTMLDivElement>();
// or
const observer = useIntersectionObserver(ref, { threshold: 0.5 });
Example
import { useIntersectionObserver } from "@siberiacancode/reactuse";

export const LazyItem = () => {
  const observer = useIntersectionObserver<HTMLDivElement>({ threshold: 0.5 });
  const isVisible = observer.entries?.[0]?.isIntersecting ?? false;

  return <div ref={observer.ref}>{isVisible ? "Visible" : "Hidden"}</div>;
};

enabled:

Toggle observer.

const observer = useIntersectionObserver<HTMLDivElement>({ enabled: false });

onChange:

Observer callback.

const observer = useIntersectionObserver<HTMLDivElement>({
  onChange: (entries) => console.log(entries),
});

root:

Scroll container.

const observer = useIntersectionObserver<HTMLDivElement>({
  root: containerRef,
});

rootMargin:

Root offset.

const observer = useIntersectionObserver<HTMLDivElement>({
  rootMargin: "10px",
});

threshold:

Intersection ratio.

const observer = useIntersectionObserver<HTMLDivElement>({ threshold: 0.5 });
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseIntersectionObserverCallback = (
  entries: IntersectionObserverEntry[],
  observer: IntersectionObserver
) => void;
export interface UseIntersectionObserverOptions
  extends Omit<IntersectionObserverInit, "root"> {
  enabled?: boolean;
  onChange?: UseIntersectionObserverCallback;
  root?: HookTarget;
}
export interface UseIntersectionObserverReturn {
  entries?: IntersectionObserverEntry[];
  observer?: IntersectionObserver;
}
export interface UseIntersectionObserver {
  <Target extends Element>(
    options?: UseIntersectionObserverOptions,
    target?: never
  ): UseIntersectionObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    options?: UseIntersectionObserverOptions
  ): UseIntersectionObserverReturn;
  <Target extends Element>(
    callback: UseIntersectionObserverCallback,
    target?: never
  ): UseIntersectionObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    callback: UseIntersectionObserverCallback
  ): UseIntersectionObserverReturn;
}
export declare const useIntersectionObserver: UseIntersectionObserver;

9.7 useKeyboard

Registers keydown/keyup listeners on a target.

Usage
import { useKeyboard } from "@siberiacancode/reactuse";

const keyboardRef = useKeyboard<HTMLInputElement>((event) =>
  console.log(event.key)
);
// or
useKeyboard(ref, (event) => console.log(event.key));
Example
import { useKeyboard } from "@siberiacancode/reactuse";

export const SearchInput = () => {
  const keyboardRef = useKeyboard<HTMLInputElement>({
    onKeyDown: (event) => console.log(event.key),
  });

  return <input ref={keyboardRef} placeholder="Type..." />;
};

onKeyDown:

Keydown handler.

useKeyboard<HTMLInputElement>({ onKeyDown: (event) => console.log(event.key) });

onKeyUp:

Keyup handler.

useKeyboard<HTMLInputElement>({ onKeyUp: (event) => console.log(event.key) });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type KeyboardEventHandler = (event: KeyboardEvent) => void;
export interface UseKeyboardEventOptions {
  onKeyDown?: KeyboardEventHandler;
  onKeyUp?: KeyboardEventHandler;
}
export interface UseKeyboard {
  (target: HookTarget, callback: KeyboardEventHandler): void;
  (target: HookTarget, options: UseKeyboardEventOptions): void;
  <Target extends HTMLElement>(
    callback: KeyboardEventHandler,
    target?: never
  ): StateRef<Target>;
  <Target extends HTMLElement>(
    options: UseKeyboardEventOptions,
    target?: never
  ): StateRef<Target>;
}
export declare const useKeyboard: UseKeyboard;

9.8 useKeyPress

Tracks whether specific keys are pressed.

Usage
import { useKeyPress } from "@siberiacancode/reactuse";

const keyPress = useKeyPress<HTMLDivElement>("a");
// or
const keyPress = useKeyPress(ref, "a");
Example
import { useKeyPress } from "@siberiacancode/reactuse";

export const Spacebar = () => {
  const keyPress = useKeyPress<HTMLDivElement>("a");

  return (
    <div ref={keyPress.ref}>{keyPress.pressed ? "Pressed" : "Released"}</div>
  );
};

key as array (match any):

const keyPress = useKeyPress<HTMLDivElement>(["ArrowLeft", "ArrowRight"]);

callback:

const keyPress = useKeyPress<HTMLDivElement>("Escape", (pressed, event) => {
  console.log(pressed, event.key);
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseKeyPressKey = string | string[];
export type UseKeyPressCallback = (
  pressed: boolean,
  event: KeyboardEvent
) => void;
export interface UseKeyPressReturn {
  pressed: boolean;
  ref: StateRef<Element>;
}
export interface UseKeyPress {
  (
    target: HookTarget | Window,
    key: UseKeyPressKey,
    callback?: UseKeyPressCallback
  ): UseKeyPressReturn;
  <Target extends Element>(
    key: UseKeyPressKey,
    callback?: UseKeyPressCallback,
    target?: never
  ): UseKeyPressReturn & { ref: StateRef<Target> };
}
export declare const useKeyPress: UseKeyPress;

9.9 useKeysPressed

Tracks all currently pressed keys.

Usage
import { useKeysPressed } from "@siberiacancode/reactuse";

const keysPressed = useKeysPressed();
// or
const keysPressed = useKeysPressed(ref, { enabled: true });
Example
import { useKeysPressed } from "@siberiacancode/reactuse";

export const KeysPanel = () => {
  const keysPressed = useKeysPressed<HTMLDivElement>();

  return (
    <div ref={keysPressed.ref}>
      {keysPressed.value.map((item) => item.key).join(", ") || "None"}
    </div>
  );
};

enabled:

const keysPressed = useKeysPressed<HTMLDivElement>({ enabled: false });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseKeysPressedOptions {
  enabled?: boolean;
}
export interface UseKeysPressedReturn {
  value: Array<{ key: string; code: string }>;
}
export interface UseKeysPressed {
  (
    target: HookTarget | Window,
    options?: UseKeysPressedOptions
  ): UseKeysPressedReturn;
  <Target extends Element>(
    options?: UseKeysPressedOptions
  ): UseKeysPressedReturn & { ref: StateRef<Target> };
}
export declare const useKeysPressed: UseKeysPressed;

9.10 useMouse

Tracks mouse coordinates relative to page and element. State is stored in a snapshot; the component re-renders only when you subscribe via watch() or use the optional callback.

Usage
import { useMouse } from "@siberiacancode/reactuse";

const mouse = useMouse<HTMLDivElement>();
// or
const mouse = useMouse(ref);
// with callback (no re-render needed for side effects)
const mouse = useMouse<HTMLDivElement>((value, event) =>
  console.log(value.x, value.y)
);
Example
const mouse = useMouse<HTMLDivElement>((value) => {
  document.body.style.setProperty("--mouse-x", String(value.clientX));
  document.body.style.setProperty("--mouse-y", String(value.clientY));
});
return <div ref={mouse.ref}>Cursor position -> CSS vars</div>;

Reading snapshot without re-renders (e.g. in a handler):

const mouse = useMouse<HTMLDivElement>();
return (
  <div
    ref={mouse.ref}
    onClick={() => console.log(mouse.snapshot.clientX, mouse.snapshot.clientY)}
  >
    Click to log position
  </div>
);
Notes
  • By default the hook does not re-render on mouse move, only snapshot and the optional callback are updated. To render coordinates in JSX and react to movement, subscribe via watch(): call it once per render, for example const state = mouse.watch(), then the component will re-render on mouse move.

If you do need to show position in the UI:

const mouse = useMouse<HTMLDivElement>();
const state = mouse.watch();
return (
  <div ref={mouse.ref}>
    {state.clientX}, {state.clientY}
  </div>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseMouseValue {
  clientX: number;
  clientY: number;
  elementPositionX: number;
  elementPositionY: number;
  elementX: number;
  elementY: number;
  x: number;
  y: number;
}
export interface UseMouseReturn {
  snapshot: UseMouseValue;
  watch: () => UseMouseValue;
}
export type UseMouseCallback = (value: UseMouseValue, event: Event) => void;
export interface UseMouse {
  (target: HookTarget, callback?: UseMouseCallback): UseMouseReturn;
  <Target extends Element>(
    callback?: UseMouseCallback,
    target?: never
  ): UseMouseReturn & { ref: StateRef<Target> };
  (target?: Window, callback?: UseMouseCallback): UseMouseReturn;
}
export declare const useMouse: UseMouse;

9.11 useMutationObserver

Observes DOM mutations on an element.

Usage
import { useMutationObserver } from "@siberiacancode/reactuse";

const observer = useMutationObserver<HTMLDivElement>({ childList: true });
// or
const observer = useMutationObserver(ref, { childList: true });
Example
import { useMutationObserver } from "@siberiacancode/reactuse";
import { useState } from "react";

export const AttributeWatch = () => {
  const [count, setCount] = useState(0);
  const observer = useMutationObserver<HTMLDivElement>({
    attributes: true,
    onChange: () => setCount((value) => value + 1),
  });

  return (
    <div disabled={count % 2 === 0} ref={observer.ref}>
      Changes: {count}
    </div>
  );
};

enabled:

Toggle observer.

const observer = useMutationObserver<HTMLDivElement>({ enabled: false });

onChange:

Mutation callback.

const observer = useMutationObserver<HTMLDivElement>({
  onChange: (mutations) => console.log(mutations),
});

attributes:

Watch attributes.

const observer = useMutationObserver<HTMLDivElement>({ attributes: true });

characterData:

Watch text.

const observer = useMutationObserver<HTMLDivElement>({ characterData: true });

childList:

Watch children.

const observer = useMutationObserver<HTMLDivElement>({ childList: true });

subtree:

Watch descendants.

const observer = useMutationObserver<HTMLDivElement>({ subtree: true });
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseMutationObserverCallback = (
  mutations: MutationRecord[],
  observer: MutationObserver
) => void;
export interface UseMutationObserverOptions extends MutationObserverInit {
  enabled?: boolean;
  onChange?: UseMutationObserverCallback;
}
export interface UseMutationObserverReturn {
  observer?: MutationObserver;
}
export interface UseMutationObserver {
  <Target extends Element>(
    options?: UseMutationObserverOptions,
    target?: never
  ): UseMutationObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    options?: UseMutationObserverOptions
  ): UseMutationObserverReturn;
  <Target extends Element>(
    callback: UseMutationObserverCallback,
    target?: never
  ): UseMutationObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    callback: UseMutationObserverCallback
  ): UseMutationObserverReturn;
}
export declare const useMutationObserver: UseMutationObserver;

9.12 useOrientation

Returns the current screen orientation and lock controls.

Usage
import { useOrientation } from "@siberiacancode/reactuse";

const orientation = useOrientation();

callback:

const orientation = useOrientation((value) => {
  console.log(value.orientationType);
});
Example
import { useOrientation } from "@siberiacancode/reactuse";

export const ScreenOrientation = () => {
  const orientation = useOrientation();
  if (!orientation.supported) return <div>Not supported</div>;

  return (
    <div>
      {orientation.value.orientationType}
      <button onClick={() => orientation.lock("portrait")}>Lock</button>
      <button onClick={() => orientation.unlock()}>Unlock</button>
    </div>
  );
};
Notes
Type Declarations
export interface UseOrientationValue {
  angle: number;
  orientationType?: OrientationType;
}
export type OrientationLockType =
  | "any"
  | "landscape-primary"
  | "landscape-secondary"
  | "landscape"
  | "natural"
  | "portrait-primary"
  | "portrait-secondary"
  | "portrait";
export interface useOrientationReturn {
  supported: boolean;
  value: UseOrientationValue;
  lock: (orientation: OrientationLockType) => void;
  unlock: () => void;
}
export declare const useOrientation: (
  callback?: (value: UseOrientationValue) => void
) => useOrientationReturn;

9.13 usePageLeave

Detects when the mouse leaves the page.

Usage
import { usePageLeave } from "@siberiacancode/reactuse";

const left = usePageLeave();
Example
const left = usePageLeave();
return <div>{left ? "Leaving" : "Here"}</div>;
Type Declarations
export declare const usePageLeave: (callback?: () => void) => boolean;

9.14 useParallax

Creates a parallax effect based on mouse or device orientation.

Usage
import { useParallax } from "@siberiacancode/reactuse";

const parallax = useParallax<HTMLDivElement>();
// or
const parallax = useParallax(ref, { mouseRollAdjust: (value) => value * 0.5 });
Example
import { useParallax } from "@siberiacancode/reactuse";

const parallax = useParallax<HTMLDivElement>();
return (
  <div
    ref={parallax.ref}
    style={{
      transform: `translate(${parallax.value.roll * 5}px, ${
        parallax.value.tilt * 5
      }px)`,
    }}
  >
    Parallax
  </div>
);

mouseRollAdjust:

Mouse roll.

const parallax = useParallax<HTMLDivElement>({
  mouseRollAdjust: (value) => value * 0.5,
});

mouseTiltAdjust:

Mouse tilt.

const parallax = useParallax<HTMLDivElement>({
  mouseTiltAdjust: (value) => value * 0.5,
});

deviceOrientationRollAdjust:

Device roll.

const parallax = useParallax<HTMLDivElement>({
  deviceOrientationRollAdjust: (value) => value * 0.5,
});

deviceOrientationTiltAdjust:

Device tilt.

const parallax = useParallax<HTMLDivElement>({
  deviceOrientationTiltAdjust: (value) => value * 0.5,
});
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseParallaxValue {
  roll: number;
  source: "deviceOrientation" | "mouse";
  tilt: number;
}
export interface UseParallaxOptions {
  deviceOrientationRollAdjust?: (value: number) => number;
  deviceOrientationTiltAdjust?: (value: number) => number;
  mouseRollAdjust?: (value: number) => number;
  mouseTiltAdjust?: (value: number) => number;
}
interface UseParallaxReturn {
  value: UseParallaxValue;
}
export interface UseParallax {
  (target: HookTarget, options?: UseParallaxOptions): UseParallaxReturn;
  <Target extends Element>(
    options?: UseParallaxOptions,
    target?: never
  ): UseParallaxReturn & { ref: StateRef<Target> };
}
export declare const useParallax: UseParallax;

9.15 usePerformanceObserver

Observes performance entries.

Usage
import { usePerformanceObserver } from "@siberiacancode/reactuse";

const perf = usePerformanceObserver({ entryTypes: ["measure"] });
Example
import { usePerformanceObserver } from "@siberiacancode/reactuse";

export const PerfEntries = () => {
  const perf = usePerformanceObserver({ entryTypes: ["resource"] });

  return (
    <div>
      Entries: {perf.entries.length} (supported: {String(perf.supported)})
    </div>
  );
};

immediate:

const perf = usePerformanceObserver({
  entryTypes: ["resource"],
  immediate: true,
});

entryTypes:

const perf = usePerformanceObserver({ entryTypes: ["navigation"] });
Notes
Type Declarations
export type UsePerformanceObserverOptions = PerformanceObserverInit & {
  immediate?: boolean;
};
export declare const usePerformanceObserver: (
  options: UsePerformanceObserverOptions,
  callback?: PerformanceObserverCallback
) => {
  supported: boolean;
  entries: PerformanceEntry[];
  start: () => void;
  stop: () => void;
};

9.16 useResizeObserver

Observes size changes for an element.

Usage
import { useResizeObserver } from "@siberiacancode/reactuse";

const observer = useResizeObserver<HTMLDivElement>();
// or
const observer = useResizeObserver(ref, { box: "border-box" });
Example
import { useResizeObserver } from "@siberiacancode/reactuse";

const observer = useResizeObserver<HTMLDivElement>();
const entry = observer.entry;

return (
  <div ref={observer.ref}>
    {observer.entry?.contentRect.width}x{observer.entry?.contentRect.height}
  </div>
);

enabled:

Toggle observer.

const observer = useResizeObserver<HTMLDivElement>({ enabled: false });

box:

Box sizing.

const observer = useResizeObserver<HTMLDivElement>({ box: "border-box" });

onChange:

Resize callback.

const observer = useResizeObserver<HTMLDivElement>({
  onChange: (entry) => console.log(entry),
});
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseResizeObserverCallback = (
  entry: ResizeObserverEntry,
  observer: ResizeObserver
) => void;
export interface UseResizeObserverOptions extends ResizeObserverOptions {
  enabled?: boolean;
  onChange?: UseResizeObserverCallback;
}
export interface UseResizeObserverReturn {
  entry: ResizeObserverEntry;
  observer?: ResizeObserver;
}
export interface UseResizeObserver {
  <Target extends Element>(
    options?: UseResizeObserverOptions,
    target?: never
  ): UseResizeObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    options?: UseResizeObserverOptions
  ): UseResizeObserverReturn;
  <Target extends Element>(
    callback: UseResizeObserverCallback,
    target?: never
  ): UseResizeObserverReturn & { ref: StateRef<Target> };
  (
    target: HookTarget,
    callback: UseResizeObserverCallback
  ): UseResizeObserverReturn;
}
export declare const useResizeObserver: UseResizeObserver;

9.17 useScroll

Tracks scroll state and provides scroll helpers.

Usage
import { useScroll } from "@siberiacancode/reactuse";

const scroll = useScroll<HTMLDivElement>();
// or
const scroll = useScroll(ref);
Example
const scroll = useScroll<HTMLDivElement>({
  onScroll: ({ arrived, y }) => {
    if (arrived.bottom) console.log("reached bottom");
  },
});
return (
  <div ref={scroll.ref}>
    <button onClick={() => scroll.scrollTo({ x: 0, y: 0 })}>Top</button>
    <button onClick={() => scroll.scrollIntoView({ block: "end" })}>To end</button>
  </div>
);

onStop:

const scroll = useScroll<HTMLDivElement>({
  onStop: () => console.log("stopped"),
});

offset:

const scroll = useScroll<HTMLDivElement>({ offset: { left: 10, top: 10 } });
Notes
  • By default the hook does not re-render on scroll, only snapshot in a ref and onScroll are updated. To render scroll state in JSX and react to changes, subscribe via watch(): call it once per render, for example const state = scroll.watch(), then the component will re-render on scroll and state will stay in sync.

If you do need to show scroll position in the UI:

const scroll = useScroll<HTMLDivElement>();
const state = scroll.watch();

return (
  <div ref={scroll.ref}>
    Scroll: {state.y}px · {state.arrived.bottom ? "Bottom" : "scrolling"}
  </div>
);
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseScrollOptions {
  offset?: {
    left?: number;
    right?: number;
    top?: number;
    bottom?: number;
  };
  onScroll?: (params: UseScrollCallbackParams, event: Event) => void;
  onStop?: (event: Event) => void;
}
export interface UseScrollCallbackParams {
  arrived: {
    left: boolean;
    right: boolean;
    top: boolean;
    bottom: boolean;
  };
  directions: {
    left: boolean;
    right: boolean;
    top: boolean;
    bottom: boolean;
  };
  x: number;
  y: number;
}
export interface ScrollIntoViewParams {
  behavior?: ScrollBehavior;
  block?: ScrollLogicalPosition;
  inline?: ScrollLogicalPosition;
}
export interface ScrollToParams {
  behavior?: ScrollBehavior;
  x: number;
  y: number;
}
export interface UseScrollReturn {
  snapshot: UseScrollCallbackParams;
  scrollIntoView: (params?: ScrollIntoViewParams) => void;
  scrollTo: (params?: ScrollToParams) => void;
  watch: () => UseScrollCallbackParams;
}
export interface UseScroll {
  (
    target?: HookTarget,
    callback?: (params: UseScrollCallbackParams, event: Event) => void
  ): UseScrollReturn;
  (target: HookTarget, options?: UseScrollOptions): UseScrollReturn;
  <Target extends Element>(
    callback?: (params: UseScrollCallbackParams, event: Event) => void,
    target?: never
  ): UseScrollReturn & { ref: StateRef<Target> };
  <Target extends Element>(
    options?: UseScrollOptions,
    target?: never
  ): UseScrollReturn & { ref: StateRef<Target> };
}
export declare const useScroll: UseScroll;

9.18 useScrollIntoView

Scrolls an element into view and exposes a trigger.

Usage
import { useScrollIntoView } from "@siberiacancode/reactuse";

const scrollIntoView = useScrollIntoView<HTMLDivElement>();
// or
useScrollIntoView(ref, { behavior: "smooth" });
Example
import { useScrollIntoView } from "@siberiacancode/reactuse";

export const JumpToDetails = () => {
  const scrollIntoView = useScrollIntoView<HTMLDivElement>({
    behavior: "smooth",
  });

  return (
    <div>
      <button onClick={() => scroll.trigger()}>Go to details</button>
      <div ref={scrollIntoView.ref}>Details</div>
    </div>
  );
};

immediately:

Run immediately.

const scrollIntoView = useScrollIntoView<HTMLDivElement>({
  immediately: false,
});

behavior:

Scroll behavior.

const scrollIntoView = useScrollIntoView<HTMLDivElement>({
  behavior: "smooth",
});

block:

Block alignment.

const scrollIntoView = useScrollIntoView<HTMLDivElement>({ block: "center" });

inline:

Inline alignment.

const scrollIntoView = useScrollIntoView<HTMLDivElement>({ inline: "center" });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseScrollIntoViewOptions extends ScrollIntoViewOptions {
  immediately?: boolean;
}
export interface UseScrollIntoViewReturn {
  trigger: (params?: {
    behavior?: ScrollBehavior;
    block?: ScrollLogicalPosition;
    inline?: ScrollLogicalPosition;
  }) => void;
}
export interface UseScrollIntoView {
  <Target extends Element>(
    options?: UseScrollIntoViewOptions,
    target?: never
  ): UseScrollIntoViewReturn & { ref: StateRef<Target> };
  (
    target?: HookTarget,
    options?: UseScrollIntoViewOptions
  ): UseScrollIntoViewReturn;
}
export declare const useScrollIntoView: UseScrollIntoView;

9.19 useScrollTo

Scrolls to a specific position with a trigger.

Usage
import { useScrollTo } from "@siberiacancode/reactuse";

const scrollTo = useScrollTo<HTMLDivElement>({ x: 0, y: 0 });
// or
useScrollTo(ref, { x: 0, y: 0 });
Example
import { useScrollTo } from "@siberiacancode/reactuse";

export const BackToTop = () => {
  const scrollTo = useScrollTo<HTMLDivElement>({ x: 0, y: 0 });

  return <button onClick={() => scrollTo.trigger()}>Top</button>;
};

immediately:

Run immediately.

const scrollTo = useScrollTo<HTMLDivElement>({
  x: 0,
  y: 0,
  immediately: false,
});

behavior:

Scroll behavior.

const scrollTo = useScrollTo<HTMLDivElement>({
  x: 0,
  y: 0,
  behavior: "smooth",
});

x:

Target x.

const scrollTo = useScrollTo<HTMLDivElement>({ x: 200, y: 0 });

y:

Target y.

const scrollTo = useScrollTo<HTMLDivElement>({ x: 0, y: 300 });
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export interface UseScrollToOptions {
  behavior?: ScrollBehavior;
  immediately?: boolean;
  x: number;
  y: number;
}
export interface UseScrollToReturn {
  trigger: (params?: {
    x: number;
    y: number;
    behavior?: ScrollBehavior;
  }) => void;
}
export interface UseScrollTo {
  <Target extends Element>(
    options?: UseScrollToOptions,
    target?: never
  ): UseScrollToReturn & { ref: StateRef<Target> };
  (target?: HookTarget, options?: UseScrollToOptions): UseScrollToReturn;
}
export declare const useScrollTo: UseScrollTo;

9.20 useSwipe

Turns touch and pointer movement into swipe direction and distance state for gesture-driven UI.

Usage
import { useSwipe } from "@siberiacancode/reactuse";

const swipe = useSwipe<HTMLDivElement>((value) => console.log(value.direction));
// or
const swipe = useSwipe(ref, { threshold: 80 });
Example
import { useSwipe } from "@siberiacancode/reactuse";

export const SwipeCard = () => {
  const swipe = useSwipe<HTMLDivElement>();
  const value = swipe.watch();

  return (
    <div ref={swipe.ref}>
      {swipe.swiping ? value.direction : "Swipe left or right"}
    </div>
  );
};

callback:

const swipe = useSwipe<HTMLDivElement>((value) => console.log(value.direction));

target:

const swipe = useSwipe(target("#carousel"), { threshold: 80 });

threshold:

const swipe = useSwipe<HTMLDivElement>({ threshold: 80 });

onStart:

const swipe = useSwipe<HTMLDivElement>({
  onStart: (value) => console.log(value.direction),
});

onMove:

const swipe = useSwipe<HTMLDivElement>({
  onMove: (value) => console.log(value.lengthX),
});

onEnd:

const swipe = useSwipe<HTMLDivElement>({
  onEnd: (value) => console.log(value.direction),
});
Notes
  • By default gesture movement updates snapshot and callbacks without forcing a re-render. To render live swipe state in JSX, subscribe via watch(): call it once per render, for example const value = swipe.watch(), then the component will re-render while swiping.
Type Declarations
import type { HookTarget, StateRef } from "@siberiacancode/reactuse";

export type SwipeDirection = "down" | "left" | "none" | "right" | "up";
export type SwipeEvent = PointerEvent | TouchEvent;
export interface UseSwipeValue {
  direction: SwipeDirection;
  lengthX: number;
  lengthY: number;
}
export type UseSwipeCallback = (value: UseSwipeValue, event: SwipeEvent) => void;
export interface UseSwipeOptions {
  onMove?: UseSwipeCallback;
  threshold?: number;
  onEnd?: (value: UseSwipeValue, event: SwipeEvent) => void;
  onStart?: (value: UseSwipeValue, event: SwipeEvent) => void;
}
export interface UseSwipeReturn {
  snapshot: UseSwipeValue;
  swiping: boolean;
  watch: () => UseSwipeValue;
}
export interface UseSwipe {
  (target: HookTarget, callback?: UseSwipeCallback): UseSwipeReturn;
  (target: HookTarget, options?: UseSwipeOptions): UseSwipeReturn;
  <Target extends Element>(
    callback?: UseSwipeCallback
  ): UseSwipeReturn & { ref: StateRef<Target> };
  <Target extends Element>(
    options?: UseSwipeOptions
  ): UseSwipeReturn & { ref: StateRef<Target> };
}
export declare const useSwipe: UseSwipe;

9.21 useTextSelection

Tracks text selection details.

Usage
import { useTextSelection } from "@siberiacancode/reactuse";

const selection = useTextSelection();
Example
import { useTextSelection } from "@siberiacancode/reactuse";

export const SelectedText = () => {
  const selection = useTextSelection();
  return (
    <span>
      {selection.text ? `Selected: ${selection.text}` : "Select text"}
    </span>
  );
};
Notes
Type Declarations
export interface UseTextSelectionReturn {
  ranges: Range[];
  rects: DOMRect[];
  selection: Selection | null;
  text: string;
}
export declare const useTextSelection: () => UseTextSelectionReturn;

9.22 useVisibility

Tracks whether an element is visible in the viewport.

Usage
import { useVisibility } from "@siberiacancode/reactuse";

const visibility = useVisibility<HTMLDivElement>();
// or
const visibility = useVisibility<HTMLDivElement>(ref, { threshold: 0.5 });
Example
import { useVisibility } from "@siberiacancode/reactuse";

export const VisibilityBadge = () => {
  const visibility = useVisibility<HTMLDivElement>();

  return (
    <div ref={visibility.ref}>
      {visibility.inView ? "In view" : "Out of view"}
    </div>
  );
};

enabled:

const visibility = useVisibility<HTMLDivElement>({ enabled: false });

onChange:

const visibility = useVisibility<HTMLDivElement>({
  onChange: (entry) => console.log(entry),
});

root:

const visibility = useVisibility<HTMLDivElement>({ root: containerRef });

rootMargin:

const visibility = useVisibility<HTMLDivElement>({ rootMargin: "10px" });

threshold:

const visibility = useVisibility<HTMLDivElement>({ threshold: 0.5 });
Notes
Type Declarations
import type { HookTarget } from "@siberiacancode/reactuse";
import type { StateRef } from "@siberiacancode/reactuse";

export type UseVisibilityCallback = (
  entry: IntersectionObserverEntry,
  observer: IntersectionObserver
) => void;
export interface UseVisibilityOptions
  extends Omit<IntersectionObserverInit, "root"> {
  enabled?: boolean;
  onChange?: UseVisibilityCallback;
  root?: HookTarget;
}
export interface UseVisibilityReturn {
  entry?: IntersectionObserverEntry;
  inView: boolean;
  observer?: IntersectionObserver;
}
export interface UseVisibility {
  <Target extends Element>(
    options?: UseVisibilityOptions,
    target?: never
  ): UseVisibilityReturn & { ref: StateRef<Target> };
  (target: HookTarget, options?: UseVisibilityOptions): UseVisibilityReturn;
  <Target extends Element>(
    callback: UseVisibilityCallback,
    target?: never
  ): UseVisibilityReturn & { ref: StateRef<Target> };
  (target: HookTarget, callback: UseVisibilityCallback): UseVisibilityReturn;
}
export declare const useVisibility: UseVisibility;

9.23 useWindowEvent

Attaches an event listener to the window object.

Usage
import { useWindowEvent } from "@siberiacancode/reactuse";

useWindowEvent("resize", () => console.log("resize"));
Example
import { useWindowEvent } from "@siberiacancode/reactuse";
import { useState } from "react";

export const ResizeCount = () => {
  const [count, setCount] = useState(0);
  useWindowEvent("resize", () => setCount((value) => value + 1));

  return <div>Resized: {count}</div>;
};

enabled:

useWindowEvent("scroll", () => {}, { enabled: false });
Type Declarations
import type { UseEventListenerOptions } from "@siberiacancode/reactuse";

export declare const useWindowEvent: <Event extends keyof WindowEventMap>(
  event: Event,
  listener: (this: Window, event: WindowEventMap[Event]) => any,
  options?: UseEventListenerOptions
) => void;

9.24 useWindowScroll

Tracks window scroll position and exposes scrollTo.

Usage
import { useWindowScroll } from "@siberiacancode/reactuse";

const scroll = useWindowScroll();
Example
import { useWindowScroll } from "@siberiacancode/reactuse";

export const ScrollButton = () => {
  const windowScroll = useWindowScroll();
  return (
    <button onClick={() => windowScroll.scrollTo({ y: 0 })}>
      Top (y: {windowScroll.value.y})
    </button>
  );
};
Type Declarations
export interface ScrollPosition {
  x: number;
  y: number;
}
export declare const scrollTo: (
  params: Partial<ScrollPosition & ScrollOptions>
) => void;
export declare const useWindowScroll: () => {
  value: ScrollPosition;
  scrollTo: typeof scrollTo;
};

10. Time

10.1 useInterval

Creates an interval with controls to pause and resume it.

Usage
import { useInterval } from "@siberiacancode/reactuse";

const interval = useInterval(() => console.log("tick"), 2500);
Example
import { useInterval } from "@siberiacancode/reactuse";
import { useState } from "react";

export const Ticker = () => {
  const [count, setCount] = useState(0);
  const interval = useInterval(() => setCount((value) => value + 1), 1000);

  return (
    <button onClick={() => interval.toggle()}>
      {interval.active ? "Pause" : "Resume"} ({count})
    </button>
  );
};

interval (milliseconds):

const interval = useInterval(() => console.log("tick"), 2000);

immediately (start right away):

const interval = useInterval(() => console.log("tick"), {
  interval: 1000,
  immediately: false,
});
Type Declarations
export interface UseIntervalOptions {
  immediately?: boolean;
}
export interface UseIntervalReturn {
  active: boolean;
  pause: () => void;
  resume: () => void;
  toggle: () => void;
}
interface UseInterval {
  (
    callback: () => void,
    interval?: number,
    options?: UseIntervalOptions
  ): UseIntervalReturn;
  (
    callback: () => void,
    options?: UseIntervalOptions & { interval?: number }
  ): UseIntervalReturn;
}
export declare const useInterval: UseInterval;

10.2 useProgress

Creates a lightweight progress state with auto-increment behavior.

Usage
import { useProgress } from "@siberiacancode/reactuse";

const { value, active, start, done, inc, remove } = useProgress(0, {
  immediately: false,
  maximum: 0.98,
  speed: 250,
  rate: 0.02,
});
Example
import { useProgress } from "@siberiacancode/reactuse";

export const LoadingBar = () => {
  const progress = useProgress(0);

  const onLoad = async () => {
    progress.start();
    await new Promise((resolve) => setTimeout(resolve, 1200));
    progress.done();
  };

  return (
    <div>
      <button onClick={onLoad}>Start</button>

      {active && (
        <div
          style={{
            width: "100%",
            height: 4,
            background: "#e5e7eb",
            marginTop: 12,
          }}
        >
          <div
            style={{
              width: `${Math.round(value * 100)}%`,
              height: "100%",
              background: "#2563eb",
              transition: "width 200ms ease",
            }}
          />
        </div>
      )}
    </div>
  );
};

initialValue:

Initial progress value in the 0..1 range.

const progress = useProgress(0.25);

immediately:

Starts progress automatically on mount.

const progress = useProgress(0, { immediately: true });

maximum:

Upper bound for auto-increment while active.

const progress = useProgress(0, { maximum: 0.95 });

speed:

Auto-increment interval in milliseconds.

const progress = useProgress(0, { speed: 150 });

rate:

Additional random increment amount per tick.

const progress = useProgress(0, { rate: 0.03 });
Use cases
  • Top-page loading bars for route/data transitions.
Notes
  • value is expected in the 0..1 range.
  • done() sets progress to 1 and disables active state with a short delay.
Type Declarations
export interface UseProgressOptions {
  immediately?: boolean;
  maximum?: number;
  rate?: number;
  speed?: number;
}
export interface UseProgressReturn {
  active: boolean;
  value: number;
  done: (force?: boolean) => number | null;
  inc: (amount?: number) => number | null;
  remove: () => void;
  start: (from?: number | null) => number;
}
export declare const useProgress: (
  initialValue?: number,
  options?: UseProgressOptions
) => UseProgressReturn;

10.3 useStopwatch

Creates a stopwatch with start, pause, and reset controls.

Usage
import { useStopwatch } from "@siberiacancode/reactuse";

const stopwatch = useStopwatch();
Example
import { useStopwatch } from "@siberiacancode/reactuse";

export const Stopwatch = () => {
  const stopwatch = useStopwatch();

  return (
    <div>
      {stopwatch.minutes}:{stopwatch.seconds}
      <button onClick={() => stopwatch.toggle()}>
        {stopwatch.paused ? "Start" : "Pause"}
      </button>
    </div>
  );
};

initialTime:

Start from a value.

const stopwatch = useStopwatch(120);

immediately:

Auto-start.

const stopwatch = useStopwatch({ initialTime: 0, immediately: true });
Type Declarations
export interface UseStopwatchReturn {
  count: number;
  days: number;
  hours: number;
  minutes: number;
  over: boolean;
  paused: boolean;
  seconds: number;
  pause: () => void;
  reset: () => void;
  start: () => void;
  toggle: () => void;
}
export interface UseStopwatchOptions {
  immediately?: boolean;
}
interface UseStopwatch {
  (initialTime?: number, options?: UseStopwatchOptions): UseStopwatchReturn;
  (
    options?: UseStopwatchOptions & { initialTime?: number }
  ): UseStopwatchReturn;
}
export declare const useStopwatch: UseStopwatch;

10.4 useTime

Provides the current time split into multiple fields.

Usage
import { useTime } from "@siberiacancode/reactuse";

const time = useTime();
Example
import { useTime } from "@siberiacancode/reactuse";

export const Clock = () => {
  const time = useTime();
  return (
    <div>
      {String(time.hours).padStart(2, "0")}:
      {String(time.minutes).padStart(2, "0")}:
      {String(time.seconds).padStart(2, "0")}
    </div>
  );
};
Type Declarations
export interface UseTimeReturn {
  day: number;
  hours: number;
  meridiemHours: { value: number; type: string };
  minutes: number;
  month: number;
  seconds: number;
  timestamp: number;
  year: number;
}
export declare const useTime: () => UseTimeReturn;

10.5 useTimeout

Runs a callback after a delay and returns a ready flag.

Usage
import { useTimeout } from "@siberiacancode/reactuse";

const timeout = useTimeout(() => {}, 5000);
const paused = useTimeout(() => {}, undefined);
Example
import { useTimeout } from "@siberiacancode/reactuse";

export const Toast = () => {
  const timeout = useTimeout(() => {
    console.log("hide");
  }, 2000);

  return (
    <div>
      {timeout.ready ? "Hidden" : "Visible"}
      <button onClick={() => timeout.clear()}>Dismiss</button>
    </div>
  );
};
Type Declarations
interface UseTimeoutReturn {
  ready: boolean;
  clear: () => void;
}
export declare function useTimeout(
  callback: () => void,
  delay?: number
): UseTimeoutReturn;

10.6 useTimer

Creates a countdown timer with controls and callbacks.

Usage
import { useTimer } from "@siberiacancode/reactuse";

const timer = useTimer(60);
Example
import { useTimer } from "@siberiacancode/reactuse";

export const Countdown = () => {
  const timer = useTimer(10);

  return (
    <div>
      {timer.seconds}s
      <button onClick={() => timer.toggle()}>
        {timer.active ? "Pause" : "Resume"}
      </button>
    </div>
  );
};

seconds:

Initial countdown.

const timer = useTimer(30);

immediately:

Auto-start.

const timer = useTimer(30, { immediately: false });

onExpire:

When timer ends.

const timer = useTimer(10, {
  onExpire: () => console.log("done"),
});

onStart:

When timer starts.

const timer = useTimer(10, {
  onStart: () => console.log("start"),
});

onTick:

On each second.

const timer = useTimer(10, {
  onTick: (seconds) => console.log(seconds),
});
Type Declarations
export type PositiveInteger<Value extends number> = `${Value}` extends
  | `-${any}`
  | `${any}.${any}`
  ? never
  : Value;
export interface UseTimerOptions {
  immediately?: boolean;
  onExpire?: () => void;
  onStart?: () => void;
  onTick?: (seconds: number) => void;
}
export interface UseTimerReturn {
  active: boolean;
  count: number;
  days: number;
  hours: number;
  minutes: number;
  seconds: number;
  clear: () => void;
  decrease: (seconds: PositiveInteger<number>) => void;
  increase: (seconds: PositiveInteger<number>) => void;
  pause: () => void;
  restart: (time: PositiveInteger<number>, immediately?: boolean) => void;
  resume: () => void;
  start: () => void;
  toggle: () => void;
}
export interface UseTimer {
  (): UseTimerReturn;
  (seconds: PositiveInteger<number>, callback: () => void): UseTimerReturn;
  (seconds: PositiveInteger<number>, options?: UseTimerOptions): UseTimerReturn;
}
export declare const useTimer: UseTimer;

11. Debug

11.1 useLogger

Logs mount, update, and unmount for a component.

Usage
import { useLogger } from "@siberiacancode/reactuse";

useLogger("Component", [value]);
Example
import { useLogger } from "@siberiacancode/reactuse";
import { useState } from "react";

export const DebugPanel = () => {
  const [count, setCount] = useState(0);
  useLogger("DebugPanel");
  return (
    <button onClick={() => setCount((value) => value + 1)}>
      Panel ({count})
    </button>
  );
};
Type Declarations
export declare const useLogger: (name: string, params: unknown[]) => void;

11.2 useRenderCount

Returns how many times a component has rendered.

Usage
import { useRenderCount } from "@siberiacancode/reactuse";

const count = useRenderCount();
Example
import { useRenderCount } from "@siberiacancode/reactuse";
import { useState } from "react";

export const RenderCounter = () => {
  const renders = useRenderCount();
  const [, setTick] = useState(0);
  return (
    <div>
      Renders: {renders}
      <button onClick={() => setTick((value) => value + 1)}>Re-render</button>
    </div>
  );
};
Type Declarations
export declare const useRenderCount: () => number;

11.3 useRenderInfo

Provides render count and timing info, with optional logging.

Usage
import { useRenderInfo } from "@siberiacancode/reactuse";

const info = useRenderInfo("Component");
Example

name (custom component name):

const info = useRenderInfo("ProfileCard");
return (
  <div>
    Renders: {info.renders}, Since last: {info.sinceLast}ms
  </div>
);

log (disable console output):

const info = useRenderInfo("ProfileCard", false);
Type Declarations
export interface UseRenderInfoReturn {
  component: string;
  renders: number;
  sinceLast: number;
  timestamp: number | null;
}
export declare const useRenderInfo: (
  name?: string,
  log?: boolean
) => UseRenderInfoReturn;

11.4 useRerender

Forces a component rerender on demand.

Usage
import { useRerender } from "@siberiacancode/reactuse";

const rerender = useRerender();
Example
import { useRerender } from "@siberiacancode/reactuse";
import { useState } from "react";

export const ManualRefresh = () => {
  const rerender = useRerender();
  const [count, setCount] = useState(0);
  return (
    <button
      onClick={() => {
        setCount((value) => value + 1);
        rerender();
      }}
    >
      Refresh {count}
    </button>
  );
};
Type Declarations
export declare const useRerender: () => () => void;

Source: SKILL.md on GitHub

No alerts16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive documentation and implementation guide for the Reactuse hook library, designed for React and Next.js projects. It provides clear rules, usage examples, and type declarations for a wide range of hooks, including those interacting with browser APIs. No malicious patterns, obfuscation, or security risks were detected.

  • Socket5mo

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    1/166 files flagged

Signed by skilld at a090849. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated last month
metadata
{
  "author": "siberiacancode",
  "version": "1.0.16"
}

README badge

README badge for siberiacancode/agent-skills/reactuse