Skip to content

refactor: use base ui useControlled for controlled state - #966

Open
Shreyag02 wants to merge 3 commits into
mainfrom
refactor/use-controlled
Open

Shreyag02 wants to merge 3 commits into
mainfrom
refactor/use-controlled

Conversation

@Shreyag02

@Shreyag02 Shreyag02 commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Use Base UI's useControlled for the controlled and uncontrolled state of Sidebar, Sidebar.Group, Select, DataView, Menu, ContextMenu and their submenus, Combobox value and inputValue, Command, CodeBlock, ColorPicker value and mode, and RangePicker value, in place of the hand-written merges. Tour, Reasoning, ChatPanel, PromptInput and CalendarPreview already use it, so this follows them instead of adding a new hook.
  • Behavior change: these props now pick controlled or uncontrolled on the first render and keep it, as Base UI components do. A prop that is undefined on the first render and set later is ignored, and a controlled prop that later becomes undefined no longer falls back to internal state. Base UI logs a warning in development for both. The Base UI roots under Select, Combobox and Command already did this for value, and the value Apsara reads now matches them.
  • Fix CodeBlock calling onCollapseChange with the wrong value when collapsed is controlled, and calling it twice per click in Strict Mode.
  • Pass '' to the language Select of CodeBlock.LanguageSelect until a CodeBlock.Code sets the value, so its trigger shows the language when CodeBlock has no value or defaultValue.
  • Add tests for controlled Menu and ContextMenu, the Menu and Select search value, the ColorPicker mode, and the CodeBlock fixes.

Closes #876

@vercel

vercel Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
apsara Ready Ready Preview Oct 16, 2026 7:38am UTC

@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 51020e79-f9f5-4196-92c5-44fe760b8d54
📥 Commits

Reviewing files that changed from the base of the PR and between 0baca36 and aa0d15b.

📒 Files selected for processing: 17
  • packages/react/components/calendar/range-picker.tsx
  • packages/react/components/code-block/__tests__/code-block.test.tsx
  • packages/react/components/code-block/code-block-language-select.tsx
  • packages/react/components/code-block/code-block-root.tsx
  • packages/react/components/color-picker/__tests__/color-picker.test.tsx
  • packages/react/components/color-picker/color-picker-root.tsx
  • packages/react/components/combobox/combobox-root.tsx
  • packages/react/components/command/command-root.tsx
  • packages/react/components/context-menu/__tests__/context-menu.test.tsx
  • packages/react/components/context-menu/context-menu-root.tsx
  • packages/react/components/data-view/data-view.tsx
  • packages/react/components/menu/__tests__/menu.test.tsx
  • packages/react/components/menu/menu-root.tsx
  • packages/react/components/select/__tests__/select.test.tsx
  • packages/react/components/select/select-root.tsx
  • packages/react/components/sidebar/sidebar-group.tsx
  • packages/react/components/sidebar/sidebar-root.tsx

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

Several React components now use Base UI’s useControlled hook to manage controlled and uncontrolled state. The changes cover selection and input values, menu open state, sidebar open state, and code-block collapse state. Existing callbacks remain in place. Added tests cover controlled and uncontrolled interactions in several components.

Suggested reviewers: rohanchkrabrty

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to aa0d1

No actionable regression remains identified; this PR is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 3

Failed Failed checks: 3 warnings

Check name Status Explanation Resolution
Linked Issues check Warning The linked issue requests a shared useControllableState hook in packages/raystack/hooks, but this pull request uses Base UI's existing useControlled instead. Either implement the shared hook requested by issue #876, or update the issue linkage and description to explain why Base UI's useControlled satisfies the intended outcome.
Linked Issues check Warning Issue #876 requires a shared useControllableState hook in packages/raystack/hooks and migration of Sidebar, Select, and DataView. The PR migrates those components, but the code imports Base UI's `… Add the shared useControllableState hook in packages/raystack/hooks and migrate Sidebar, Select, and DataView to that hook, or update the linked issue to define Base UI's existing useControlled as the accepted implementation.
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 17 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Out of Scope Changes check Passed The component migrations, behavior changes, bug fixes, and tests all match the pull request objectives and description.
Out of Scope Changes check Passed The additional component migrations use the same controlled/uncontrolled state-handling change described for issue #876. The CodeBlock callback and language-select fixes address behavior exposed by th…
Title check Passed The title clearly and concisely describes the main change: replacing hand-written controlled state handling with Base UI's useControlled.
Description check Passed The description accurately summarizes the useControlled migration, behavior changes, bug fixes, tests, and linked issue.
Full details: Out of Scope Changes check

Explanation

The additional component migrations use the same controlled/uncontrolled state-handling change described for issue #876. The CodeBlock callback and language-select fixes address behavior exposed by that migration. The added tests verify the changed state behavior. No unrelated change is established by the reviewed diff.

Full details: Linked Issues check

Explanation

Issue #876 requires a shared useControllableState hook in packages/raystack/hooks and migration of Sidebar, Select, and DataView. The PR migrates those components, but the code imports Base UI's useControlled from @base-ui/utils/useControlled and does not add the requested shared hook. The implementation therefore does not meet the issue's primary hook requirement.

Resolution

Add the shared useControllableState hook in packages/raystack/hooks and migrate Sidebar, Select, and DataView to that hook, or update the linked issue to define Base UI's existing useControlled as the accepted implementation.

  • Fix all pre-merge checks with AI
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/@raystack/apsara@966

commit: aa0d15b

@@ -80,13 +81,16 @@ export const ComboboxRoot = <Value extends unknown | unknown[]>({
const resolvedRequired = required ?? fieldContext?.required;

const [inputValue, setInputValue] = useState('');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use useControlled for inputValue, with the inputValue and defaultInputValue props.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. inputValue uses useControlled with the inputValue and defaultInputValue props.

@@ -67,9 +68,12 @@ export const ColorPickerRoot = ({
const [internalColor, setInternalColor] = useState(() =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use useControlled for value, the same as mode. Do the same for RangePicker value in calendar/range-picker.tsx:128.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. value uses useControlled in ColorPicker and in RangePicker.

# Conflicts:
#	packages/react/components/command/command-root.tsx
#	packages/react/components/select/select-root.tsx

This branch was successfully deployed

1 active deployment
Preview — aa0d15be Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a shared useControllableState hook

2 participants