useControllableState
Merge controlled and uncontrolled state into one value and setter
Installation
Overview
useControllableState merges controlled and uncontrolled state into a single [value, setValue] tuple, the pattern Radix and Base UI use internally. Build components that accept value + onValueChange for controlled use, or defaultValue for uncontrolled use, without branching the component logic.
onValueChange fires synchronously during the event in both modes, once per accepted update. Functional updates are safe in both modes: uncontrolled updates resolve against an eagerly-advanced internal ref, so multiple setValue calls in one event tick compose instead of clobbering each other; controlled updates resolve against the last-committed value, since the parent owns the state. setValue is referentially stable across renders, so it is safe in dependency arrays and memoized contexts.
Usage
API Reference
Options
Returns
| Property | Type | Description |
|---|---|---|
value | T | The current value (controlled prop or internal). |
setValue | (next: T | ((prev: T) => T)) => void | Updates the value; accepts functional updates. |