This component no longer exists. It was in cubby-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-10 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
useControllableState
cubby-ui/use-controllable-stateRemovedHook
A custom React hook for controllable state.
Install it
npx shadcn@latest add https://cubby-ui.dev/r/use-controllable-state.jsonSource
1"use client";23import * as React from "react";45interface UseControllableStateParams<T> {6 /** Controlled value. When defined, the hook is in controlled mode. */7 value?: T;8 /** Initial value for uncontrolled mode. */9 defaultValue: T;10 onValueChange?: (value: T) => void;11}1213/**14 * Merges controlled and uncontrolled state into a single `[value, setValue]`15 * tuple, mirroring the pattern Radix and Base UI use internally.16 *17 * `onValueChange` fires synchronously in both modes. Functional updates are18 * safe in both modes: they resolve against an eagerly-advanced ref, so19 * multiple `setValue` calls in one event tick compose. `setValue` is20 * referentially stable across renders.21 */22export function useControllableState<T>({23 value,24 defaultValue,25 onValueChange,26}: UseControllableStateParams<T>): [T, (next: T | ((prev: T) => T)) => void] {27 const isControlled = value !== undefined;28 const [uncontrolled, setUncontrolled] = React.useState<T>(defaultValue);29 const current = isControlled ? (value as T) : uncontrolled;3031 const onChangeRef = React.useRef(onValueChange);32 // Mirrors `current`. Re-synced after every commit; eagerly advanced by33 // setValue so multiple calls in one event tick compose.34 const currentRef = React.useRef(current);35 React.useEffect(() => {36 onChangeRef.current = onValueChange;37 currentRef.current = current;38 });3940 const setValue = React.useCallback(41 (next: T | ((prev: T) => T)) => {42 const prev = currentRef.current;43 const resolved =44 typeof next === "function" ? (next as (prev: T) => T)(prev) : next;45 if (Object.is(resolved, prev)) return;46 if (isControlled) {47 // The parent owns the state, but advance the ref eagerly so a second48 // functional setValue in the same tick composes on this one instead of49 // clobbering it. The ref re-syncs from the prop at the next commit,50 // which also corrects it if the parent rejected the change.51 currentRef.current = resolved;52 onChangeRef.current?.(resolved);53 } else {54 currentRef.current = resolved;55 setUncontrolled(resolved);56 onChangeRef.current?.(resolved);57 }58 },59 [isControlled],60 );6162 return [current, setValue];63}
