raystack / raystack/apsara

Add a shared useControllableState hook

Open
#876 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement global
Dominant language
TypeScript
Stars
70
Forks
13
Avg merge
2d 5h
Merged PRs (30d)
8

Description

Summary

Components that support both controlled and uncontrolled usage each re-implement the controlled/uncontrolled merge by hand, with a slightly different shape every time. There's no shared hook for it in packages/raystack/hooks.

Current duplication

  • sidebar-root.tsx:128-129const [internalOpen, setInternalOpen] = useState(defaultOpen); const open = providedOpen ?? internalOpen;
  • select-root.tsx:113-122 — same ?? pattern, duplicated again for searchValue a few lines later.
  • data-view.tsx:73-83 — different style again: explicit isViewControlled = view !== undefined boolean instead of ??.

Components built directly on Base UI primitives (Checkbox, Switch, Tabs, Accordion, Dialog) don't have this problem — they get controlled/uncontrolled handling for free from Base UI. This only affects components with custom root logic.

Suggested approach

Add one useControllableState({ value, defaultValue, onChange }) hook to packages/raystack/hooks, modeled on @radix-ui/react-use-controllable-state. Migrate Sidebar, Select, and DataView onto it so all three follow the same merge semantics.

Notes

Found via a components.build practices audit (state management dimension).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/raystack/hooks and compare the controlled/uncontrolled patterns in sidebar-root.tsx, select-root.tsx, and data-view.tsx. Read the referenced @radix-ui/react-use-controllable-state model, then verify that Sidebar, Select, and DataView use the shared semantics consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.