Skip to content

Conversation

@franklinmdev
Copy link

Summary

Fixes spurious onValueChange calls with empty string when controlled Select value is updated externally inside a form.

Problem

When using Select as a controlled component inside a <form> and updating the value prop externally (e.g., via React Hook Form's reset()), onValueChange was being called with an empty string '', which would overwrite the valid controlled value.

Reproduction steps:

  1. Use a controlled Select inside a <form>
  2. Update the value prop externally (e.g., setValue('apple'))
  3. onValueChange is spuriously called with '' after the valid value update

Root Cause

The SelectBubbleInput component (hidden native select for form integration) has an onChange handler that receives events from the internal BubbleSelect useEffect which dispatches synthetic change events for form syncing. When the native select element hasn't fully updated with the new value, event.target.value returns empty string, triggering the spurious callback.

Solution

Guard the internal onChange handler to prevent empty value updates when a valid controlled value already exists:

onChange={(event) => {
  const newValue = event.target.value;
  // Prevent spurious empty string updates from internal sync events
  // when controlled value exists (fixes #3135)
  if (newValue !== '' || value === '' || value === undefined) {
    setValue(newValue);
  }
}}

This ensures onValueChange is only called for:

  • Genuine user interactions (selecting an option)
  • Form autofill scenarios
  • Valid programmatic clears (when value is already empty/undefined)

Testing

  • Added Storybook story ControlledInFormExternalUpdate demonstrating the fix
  • All existing tests pass (233 tests)
  • Manual testing confirms external value updates no longer trigger spurious callbacks

Changeset

Included patch changeset for @radix-ui/react-select

Fixes #3135, #3249, #3693

@changeset-bot
Copy link

changeset-bot bot commented Nov 26, 2025

🦋 Changeset detected

Latest commit: ebdac67

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@radix-ui/react-select Patch
radix-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

When a controlled Select receives a new value prop (e.g., from form.reset()),
onValueChange was incorrectly called with an empty string, overwriting the
valid controlled value.

This fix guards the internal onChange handler to skip empty value updates
when a valid controlled value exists, ensuring onValueChange only fires for
genuine user interactions or form autofill.

Fixes radix-ui#3135, radix-ui#3249, radix-ui#3693
@franklinmdev franklinmdev force-pushed the fix/select-spurious-onvaluechange branch from 200266a to ebdac67 Compare November 26, 2025 16:08
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.

Select component inside a form acts indeterminately

1 participant