Trying to implement a text input with a select that inserts options into the input (at the cursor position), I have noticed that the undo/redo behaviour is inconsistent with the browsers I tried (chrome v94, firefox 89, safari 14, edge v93)
Below is a sample code example where you can notice the difference of behaviour between two inputs, one where the value is set as is, and one where the value is transformed to uppercase
ctrl/cmd + z
works to undo and ctrl/cmd + shift + z
works to redo only in the first input
const { useState } = React;
const Example = () => {
const [text, setText] = useState("");
const [upperCaseText, setUpperCaseText] = useState("");
return (
<div className="App">
<input
type="text"
value={text}
onChange={({ target }) => setText(target.value)}
placeholder="text set as is"
/>
<input
type="text"
value={upperCaseText}
onChange={({ target }) => setUpperCaseText(target.value.toUpperCase())}
placeholder="text uppercased"
/>
</div>
)
};
ReactDOM.render(
<Example />,
document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
There is one similar post and answer here but it only works with limitations, document.execCommand
is deprecated, and not supported on firefox.
I have also tried to dispatch an event and force the input value as described here and even dispatch keydown
events, but although the input field is populated, the browsers still don't recognize those inputs as user inputs and exclude them from the input undo/redo history.
Is there a way to have browsers treat programmatic changes to the input the same way as manual user input (keypress or clipboard paste), or does one have to implement a custom input change history here?