structyl

@structyl/hooks

Hooks

24 reusable, SSR-safe, tree-shakeable React hooks. Zero dependencies. Import only what you use.

pnpm add @structyl/hooks

useBoolean

State

Boolean state with named semantic setters: on, off, toggle.

(initial?: boolean) => { value, on, off, toggle, set }
OFF

Parameters

initialStarting value. Defaults to false.
Returns { value: boolean, on, off, toggle, set }

useToggle

State

Boolean state with a single toggle function and optional value setter.

(initial?: boolean) => [boolean, toggle, setValue]
value: false

Parameters

initialStarting value. Defaults to false.
Returns [value: boolean, toggle: () => void, setValue: Dispatch<boolean>]

useCounter

State

Numeric counter with increment, decrement, reset, and custom step support.

(initial?: number) => { count, increment, decrement, reset, set }
0

Parameters

initialStarting count. Defaults to 0.
Returns { count: number, increment(by?), decrement(by?), reset, set }

usePrevious

State

Captures the value from the previous render. Useful for comparing changes.

<T>(value: T) => T | undefined

Previous

Current

0

Parameters

valueThe value to track across renders.
Returns T | undefined — undefined on the first render.

useDebounce

Performance

Delays updating a value until after a quiet period. Ideal for search inputs and API calls.

<T>(value: T, delay?: number) => T
raw""
debounced (500ms)""

Parameters

valueThe rapidly changing value.
delayQuiet period in ms. Defaults to 300.
Returns T — the debounced value.

useThrottle

Performance

Limits how often a value updates to at most once per interval.

<T>(value: T, delay?: number) => T
raw50
throttled (400ms)50

Parameters

valueThe rapidly changing value.
delayMinimum ms between updates. Defaults to 300.
Returns T — the throttled value.

useLocalStorage

Browser

State that persists in localStorage and syncs across browser tabs automatically.

<T>(key: string, initial: T) => [T, setValue, remove]
"structyl-hooks-demo": null

Parameters

keyThe localStorage key.
initialFallback when key is absent.
Returns [value: T, setValue, remove: () => void]

useCopyToClipboard

Browser

Copies text to the clipboard. Returns a timed copied state that auto-resets after 2s.

() => { copy, copied, reset }
import { useCopyToClipboard } from '@structyl/hooks';
Returns { copy: (text) => Promise<boolean>, copied: boolean, reset: () => void }

useMediaQuery

Browser

Tracks any CSS media query and returns a boolean. SSR-safe with a configurable default.

(query: string, defaultValue?: boolean) => boolean
sm ≥640pxfalse
md ≥768pxfalse
lg ≥1024pxfalse
reduced-motionfalse

Parameters

queryA valid CSS media query.
defaultValueValue returned during SSR. Defaults to false.
Returns boolean

useDarkMode

Browser

Returns true when the system prefers a dark color scheme.

() => boolean
☀️
isDark: false

Change your OS color scheme to update

Returns boolean

useWindowSize

Browser

Tracks the live viewport dimensions. SSR-safe (defaults to 0 × 0).

() => { width: number, height: number }

Width

0

px

Height

0

px

Resize the window to see it update

Returns { width: number, height: number }

useClickOutside

DOM

Fires a callback when a pointer event lands outside the referenced element. Listens to mousedown and touchstart.

<T extends HTMLElement>(ref, handler, enabled?) => void

Parameters

refRef attached to the element to watch.
handlerCalled on outside click.
enabledWhether to listen. Defaults to true.
Returns void

useHotkeys

Keyboard

Binds keyboard shortcut combinations. Supports mod (Ctrl on Windows, Cmd on Mac), shift, alt.

(keys: string, handler, options?) => void
Shift + ACtrl + KMod + Shift + P

Press a combo above…

Parameters

keysCombo string, e.g. "mod+k" or "ctrl+shift+s".
handlerCalled when the combo fires.
options.enableOnFormTagsAllow firing in inputs. Default false.
options.preventDefaultPrevent default action. Default true.
Returns void

useMount

Lifecycle

Runs a callback exactly once when the component mounts.

(callback: () => void) => void

Parameters

callbackFunction to run on mount.
Returns void

useUnmount

Lifecycle

Runs a callback on unmount. Uses a stable ref internally — safe to pass fresh closures.

(callback: () => void) => void

Parameters

callbackCleanup function.
Returns void

useUpdateEffect

Lifecycle

Like useEffect but skips the initial mount — only runs on subsequent dependency changes.

(effect: EffectCallback, deps?: DependencyList) => void
Updates fired (mount skipped)0

Parameters

effectEffect to run on updates.
depsDependency array, same as useEffect.
Returns void

useId

Utility

Generates a stable unique ID. Thin SSR-safe wrapper around React.useId with optional prefix.

(prefix?: string) => string
useId("input")input-_R_3hqnpfl5tdb_
useId("label")label-_R_3hqnpfl5tdbH1_
useId()_R_3hqnpfl5tdbH2_

Stable across re-renders · SSR-safe

Parameters

prefixOptional string prepended to the ID.
Returns string — a stable unique ID.

useControllableState

State

Bridges controlled and uncontrolled state. Lets a component accept an optional value prop without duplicating internal state logic.

<T>({ prop, defaultProp, onChange }) => [T | undefined, setter]
UncontrolledvsControlled
value = "uncontrolled"

Parameters

propExternal controlled value. Undefined means uncontrolled.
defaultPropInitial value for uncontrolled mode.
onChangeCalled whenever the value changes.
Returns [value: T | undefined, setValue]

useComposedRefs

Utility

Merges multiple refs into a single callback ref. Essential when forwarding an external ref while keeping an internal one.

<T>(...refs: Ref<T>[]) => RefCallback<T>
Click me — two refs composed here
ref1 attached: falseref2 attached: falseSame node: true · clicks: 0

Parameters

...refsAny mix of callback refs and object refs to merge.
Returns RefCallback<T> — assign to the ref prop of any element.

useCallbackRef

Utility

Returns a stable function identity that always calls the latest version of the callback. Eliminates stale-closure bugs without adding the callback to effect deps.

<T extends Fn>(callback: T | undefined) => T

Increment then log — always sees the latest count

Parameters

callbackThe fresh callback to stabilize.
Returns T — a stable reference that never changes identity.

useLatest

Utility

A ref whose .current always holds the latest value. Use inside intervals, timeouts, or event handlers to avoid reading stale closures.

<T>(value: T) => { readonly current: T }
0
Press "Read ref" to see the latest value

Parameters

valueThe value to keep perpetually current.
Returns { readonly current: T } — a ref that is always up to date.

useEventListener

DOM

Declarative addEventListener with automatic cleanup. Attaches to window by default, or any element via the optional third argument.

(event, handler, element?) => void

Press any letter key on your keyboard

waiting…

Parameters

eventDOM event name (e.g. "keydown", "scroll", "resize").
handlerEvent handler. Stabilized internally.
elementTarget. Defaults to window.
Returns void

useKeyPress

Keyboard

Fires a handler whenever a specific key is pressed. Thin wrapper around useEventListener — auto-cleans up on unmount.

(key: string, handler: (e: KeyboardEvent) => void) => void
0

Press ↑ or ↓ arrow keys

Parameters

keyKey value to watch (e.g. "Enter", "ArrowUp", "Escape").
handlerCalled when the key is pressed.
Returns void

useIsomorphicLayoutEffect

Lifecycle

SSR-safe useLayoutEffect. Uses useLayoutEffect in the browser (runs synchronously before paint) and falls back to useEffect on the server — no hydration warnings.

(effect: EffectCallback, deps?: DependencyList) => void
Measured element
0 × 0px — read before first paint

useLayoutEffect on client · useEffect on server

Parameters

effectEffect to run. Synchronous before paint on the client.
depsDependency array, same as useEffect.
Returns void