How to programmatically fill input elements built with React?

This accepted solution appears not to work in React > 15.6 (including React 16) as a result of changes to de-dupe input and change events.

You can see the React discussion here: https://github.com/facebook/react/issues/10135

And the suggested workaround here: https://github.com/facebook/react/issues/10135#issuecomment-314441175

Reproduced here for convenience:

Instead of

input.value = 'foo';
input.dispatchEvent(new Event('input', {bubbles: true}));

You would use

function setNativeValue(element, value) {
  const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
  const prototype = Object.getPrototypeOf(element);
  const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;

  if (valueSetter && valueSetter !== prototypeValueSetter) {
    prototypeValueSetter.call(element, value);
  } else {
    valueSetter.call(element, value);
  }
}

and then

setNativeValue(input, 'foo');
input.dispatchEvent(new Event('input', { bubbles: true }));

React is listening for the input event of text fields.

You can change the value and manually trigger an input event, and react's onChange handler will trigger:

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = {value: ''}
  }
  
  handleChange(e) {
    this.setState({value: e.target.value})
    console.log('State updated to ', e.target.value);
  }
  
  render() {
    return (
      <div>
        <input
          id='textfield'
          value={this.state.value}
          onChange={this.handleChange.bind(this)}
        />
        <p>{this.state.value}</p>
      </div>      
    )
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById('app')
)

document.getElementById('textfield').value = 'foo'
const event = new Event('input', { bubbles: true })
document.getElementById('textfield').dispatchEvent(event)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'></div>

Here is the cleanest possible solution for inputs, selects, checkboxes, etc. (works not only for react inputs)

/**
 * See [Modify React Component's State using jQuery/Plain Javascript from Chrome Extension](https://stackoverflow.com/q/41166005)
 * See https://github.com/facebook/react/issues/11488#issuecomment-347775628
 * See [How to programmatically fill input elements built with React?](https://stackoverflow.com/q/40894637)
 * See https://github.com/facebook/react/issues/10135#issuecomment-401496776
 *
 * @param {HTMLInputElement | HTMLSelectElement} el
 * @param {string} value
 */
function setNativeValue(el, value) {
  const previousValue = el.value;

  if (el.type === 'checkbox' || el.type === 'radio') {
    if ((!!value && !el.checked) || (!!!value && el.checked)) {
      el.click();
    }
  } else el.value = value;

  const tracker = el._valueTracker;
  if (tracker) {
    tracker.setValue(previousValue);
  }

  // 'change' instead of 'input', see https://github.com/facebook/react/issues/11488#issuecomment-381590324
  el.dispatchEvent(new Event('change', { bubbles: true }));
}

Usage:

setNativeValue(document.getElementById('name'), 'Your name');
document.getElementById('radio').click(); // or setNativeValue(document.getElementById('radio'), true)
document.getElementById('checkbox').click(); // or setNativeValue(document.getElementById('checkbox'), true)