Skip to content

fix(auto-resize): stop re-dispatching input event on programmatic value writes#3206

Merged
segunadebayo merged 3 commits into
chakra-ui:mainfrom
Arman-Luthra:fix/autoresize-controlled-textarea
Jul 20, 2026
Merged

fix(auto-resize): stop re-dispatching input event on programmatic value writes#3206
segunadebayo merged 3 commits into
chakra-ui:mainfrom
Arman-Luthra:fix/autoresize-controlled-textarea

Conversation

@Arman-Luthra

Copy link
Copy Markdown
Contributor

Closes #3204

📝 Description

autoresizeTextarea overrides the element's value setter and re-dispatches a bubbling input event on every programmatic value change. React writes .value programmatically when reconciling controlled inputs and relies on those writes being side-effect-free, so the synthesized event fires the framework's onChange a second time with the value React just restored, reverting the controlled state.

The synthetic event was added in 5bd226d (fix: autoresize + input event) to work around a real bug: the override reads the value descriptor from the prototype but defines the property on the element, which clobbers the own-property value tracker React installs at mount (inputValueTracking). With the tracker no longer seeing programmatic writes, its last-known value goes stale and React swallows the next genuine input event — the type → clear → retype case in examples/next-ts/pages/autoresize-controlled.tsx.

This PR fixes that root cause instead: the setter override now wraps the element's own value descriptor (the framework tracker) when one is present, falling back to the prototype descriptor otherwise. Programmatic writes keep flowing through the tracker, so it stays in sync and no input event needs to be synthesized. resize() was already called synchronously inside the setter, so resizing behavior is unchanged.

⛳️ Current behavior (updates)

For a controlled textarea with autoresize whose state isn't committed synchronously (input rejection, external stores/signals):

  • typing a single character fires onChange twice — once with the typed value, then again with the restored previous value, reverting the controlled state
  • with input rejection, every keystroke is reverted and the field is unusable

🚀 New behavior

  • onChange fires once per keystroke; programmatic .value writes no longer dispatch input events
  • the type → clear → retype flow fixed by 5bd226d keeps working, now via tracker sync instead of a synthesized event (covered by a regression test)

💣 Is this a breaking change (Yes/No):

No. Code that relied on receiving the synthesized input event after programmatic writes would no longer get it, but that event only existed as a workaround and is exactly what corrupts controlled inputs.

📝 Additional Information

Added unit tests in packages/utilities/auto-resize/tests/autoresize-textarea.test.ts that emulate React's value tracking and change deduplication. All four fail on main and pass with this fix. I ran the vitest suite for packages/utilities locally; I was not able to run the Playwright suite in this environment.

@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2854505

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

This PR includes changesets to release 86 packages
Name Type
@zag-js/auto-resize Patch
@zag-js/tags-input Patch
@zag-js/anatomy-icons Patch
@zag-js/anatomy Patch
@zag-js/core Patch
@zag-js/docs Patch
@zag-js/preact Patch
@zag-js/react Patch
@zag-js/solid Patch
@zag-js/svelte Patch
@zag-js/vanilla Patch
@zag-js/vue Patch
@zag-js/accordion Patch
@zag-js/angle-slider Patch
@zag-js/async-list Patch
@zag-js/avatar Patch
@zag-js/carousel Patch
@zag-js/cascade-select Patch
@zag-js/checkbox Patch
@zag-js/clipboard Patch
@zag-js/collapsible Patch
@zag-js/color-picker Patch
@zag-js/combobox Patch
@zag-js/date-input Patch
@zag-js/date-picker Patch
@zag-js/dialog Patch
@zag-js/drawer Patch
@zag-js/editable Patch
@zag-js/file-upload Patch
@zag-js/floating-panel Patch
@zag-js/hover-card Patch
@zag-js/image-cropper Patch
@zag-js/listbox Patch
@zag-js/marquee Patch
@zag-js/menu Patch
@zag-js/navigation-menu Patch
@zag-js/number-input Patch
@zag-js/pagination Patch
@zag-js/password-input Patch
@zag-js/pin-input Patch
@zag-js/popover Patch
@zag-js/presence Patch
@zag-js/progress Patch
@zag-js/qr-code Patch
@zag-js/radio-group Patch
@zag-js/rating-group Patch
@zag-js/scroll-area Patch
@zag-js/select Patch
@zag-js/signature-pad Patch
@zag-js/slider Patch
@zag-js/splitter Patch
@zag-js/steps Patch
@zag-js/switch Patch
@zag-js/tabs Patch
@zag-js/timer Patch
@zag-js/toast Patch
@zag-js/toc Patch
@zag-js/toggle-group Patch
@zag-js/toggle Patch
@zag-js/tooltip Patch
@zag-js/tour Patch
@zag-js/tree-view Patch
@zag-js/store Patch
@zag-js/types Patch
@zag-js/aria-hidden Patch
@zag-js/collection Patch
@zag-js/color-utils Patch
@zag-js/utils Patch
@zag-js/date-utils Patch
@zag-js/dismissable Patch
@zag-js/dom-query Patch
@zag-js/file-utils Patch
@zag-js/focus-trap Patch
@zag-js/focus-visible Patch
@zag-js/highlight-word Patch
@zag-js/hotkeys Patch
@zag-js/i18n-utils Patch
@zag-js/interact-outside Patch
@zag-js/json-tree-utils Patch
@zag-js/live-region Patch
@zag-js/popper Patch
@zag-js/rect-utils Patch
@zag-js/remove-scroll Patch
@zag-js/scroll-snap Patch
@zag-js/stringify-state Patch
svelte-kit-starter 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

@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
zag-nextjs Ready Ready Preview Jul 20, 2026 11:43am
zag-solid Ready Ready Preview Jul 20, 2026 11:43am
zag-svelte Ready Ready Preview Jul 20, 2026 11:43am
zag-vue Ready Ready Preview Jul 20, 2026 11:43am
zag-website Ready Ready Preview Jul 20, 2026 11:43am

Request Review

Add basic/controlled autoresize examples for Nuxt, Solid, Svelte, and
Preact, plus Playwright tests for typing and paste. Also set the Svelte
app document title.
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.

autoresizeTextarea breaks controlled inputs by re-dispatching input on programmatic .value writes

2 participants