Skip to main content

State

Hooks that manage a piece of component state — persisted, undoable, controlled/uncontrolled, or just a boolean.

useLocalStorage

State synced with localStorage. The value survives reloads and updates across tabs.

Stored value: 0

The value persists across page reloads.

const [count, setCount] = useLocalStorage('demo-count', 0);

useHistoryState

State with undo/redo support. Every setValue call snapshots the previous value; undo/redo step through that history.

Current value: 0

Change the value a few times, then use Undo/Redo to step through history.

const { value, setValue, undo, redo, canUndo, canRedo } = useHistoryState(0);

useControllableState

Backs a controlled/uncontrolled prop pair (`value`/`defaultValue`/`onChange`) with a single hook — falls back to internal state when `value` is undefined, and always calls `onChange` on updates.

Toggle the checkbox freely while uncontrolled; forcing a value switches the hook to controlled mode, mirroring that prop instead.

const [checked, setChecked] = useControllableState({
value: externalValue, // undefined = uncontrolled
defaultValue: false,
onChange: value => console.log('checked:', value),
});

usePrevious

Returns the value from the previous render — useful for comparing against the current value, e.g. to detect a false-to-true transition.

Current: 0
Previous: (none yet)
const [count, setCount] = useState(0);
const previous = usePrevious(count);

useToggle

A boolean toggle with a toggle function and a direct setter — the state shape dropdowns, collapses, drawers, and modals all share.

State: closed
const [open, toggle, setOpen] = useToggle(false);

useMultiSelect

Checkbox-style multi-select for a list, with shift-click range selection. Selection is clamped against the current item count, so it stays valid if the list shrinks.

0 selected. Click to toggle, shift-click to select a range.

const { selected, isSelected, toggle, clear } = useMultiSelect(items.length);
// shift-click range-select is mouse-only, so the modifier is captured on
// the CAPTURE phase (before Checkbox's own click-driven onChange fires)
// and read back in onChange, which fires exactly once per real toggle
// (mouse click or keyboard Space).
const shiftHeldRef = useRef(false);

<div
onClickCapture={e => {
shiftHeldRef.current = e.shiftKey;
}}
>
<Checkbox
checked={isSelected(index)}
onChange={() => toggle(index, shiftHeldRef.current)}
>
{item}
</Checkbox>
</div>;