Skip to content
Consultation

I Filled the Textarea, React Never Noticed

Adityo Guni Waluyo

The text visibly entered the textarea, yet React never saw a change. Why plain assignment fails on controlled components and how the native prototype setter fixes it.

TL;DR

Automating React apps like DeepSeek fails when you set textarea.value directly, because React replaces the setter on each element instance and swallows non-user input events. The fix: grab the native setter from HTMLTextAreaElement.prototype, call it with your text, then dispatch a bubbling input event. Since the icon-only send button has no label, press Enter instead.

I was sending a long prompt to DeepSeek chat through a Python automation script. The text visibly landed in the textarea. The send button stayed dead anyway. When my script forced a send by matching a "Send" label, the URL flipped to an empty new chat and the run was wasted.

My first guess: a stale element reference, because React re-renders and old DOM nodes drop out of the tree. I re-checked and the reference was valid. Second guess: an automation tool bug. Also wrong. The text did reach the DOM, but React itself never saw a change.

React Overrides the Setter, the DOM Stays a Ghost

Here is the part many people miss: React does not treat the DOM as the source of truth for controlled components. The value prop is the state; the DOM only mirrors it. Once a textarea is controlled, React swaps the .value setter on that element instance: not on the prototype, on the instance itself. If I force a plain assignment, the browser happily paints the text on screen. React receives nothing, because the setter that ran is React's wrapper, not the browser's own, and since I am not a user typing, the change counts as nonexistent [1].

A React contributor put it plainly in that issue: React dedupes change and input events so handlers do not fire too often. When the change did not come from a real user action, the event gets swallowed.

The Fix: Skip React, Talk to the Browser Prototype

Because React replaced the setter on the instance, the only way through is to grab the original setter from the browser's HTML prototype:

// the browser's own textarea setter, NOT the React-wrapped instance one
const nativeSetter = Object.getOwnPropertyDescriptor(
  HTMLTextAreaElement.prototype, 'value'
).set;

// force the DOM value update directly, React is not involved
nativeSetter.call(textarea, promptText);

// now tell React that something changed
textarea.dispatchEvent(new Event('input', { bubbles: true }));

When I first read this trick I assumed it was a relic for old React versions. It shows up as the accepted answer on Stack Overflow [2], and the credit actually goes to a Cypress contributor who hit the same wall in test automation. In my end-to-end run: text entered, send button lit up, no more phantom empty chat URLs. One detail matters: bubbles: true on the input event. Without it, the event never reaches the ancestor React listens at.

After the value lands, there is a second hurdle. DeepSeek's send button is an icon with no text label at all, so a locator that matches the word "Send" can never find it. The Playwright docs recommend the keyboard route for cases like this [3]: pressing Enter emits the full key sequence from keydown to keyup, and virtually every chat UI treats that as a submit signal. Once I switched from hunting for the button to pressing Enter, failed sends disappeared.

One honest note before you copy this. The native setter plus a dispatched event is a workaround against React's implementation, not a public API, so there is no cross-version guarantee. Synthetic events also carry isTrusted = false, and a strict app could check that; I have not seen DeepSeek do it, but in other apps it is worth testing first. And for a controlled component, success is not textarea.value matching your text. It is whether React's state actually accepted it [4], which you can confirm by watching the value survive the next render.

This native setter plus Enter combo is now routine in my research scripts. The product you automate does not matter much; what matters is how controlled components behave underneath.


Sources

  1. React issue #10135 — "dispatchEvent on input/textarea is ignored" (2017)
  2. SO 23892547 — "What is the best way to trigger change or input event in React" (Cypress issue #647, native setter credit)
  3. Playwright docs: Actions — Keyboard input
  4. React docs: textarea (controlled component, value + onChange)

Related articles