Skip to main content
SeleniumDecoded

Clear and Type Into a React or Angular Input Reliably

Replace the value of a framework-controlled input when clear() does not stick, using select-all plus type and the native setter fallback.

Stable Verified against Selenium 4.48.0

Problem

clear() empties the field but the framework restores the old value on the next render, or clear() followed by sendKeys results in the new text appended to the old. Controlled inputs re-render from state, and clear() does not always fire the events that update that state.

Solution

Select all and type over it, which is what a user does and always fires input events. Keep a setter-based fallback for widgets that block keyboard selection.

Select-all then type
Selenium 3 & 4 Stable
public static void replaceText(WebDriver driver, WebElement input, String text) {
input.click();
String modifier = System.getProperty("os.name").toLowerCase().contains("mac") ? Keys.COMMAND : Keys.CONTROL;
input.sendKeys(Keys.chord(modifier, "a"), Keys.DELETE);
input.sendKeys(text);
// Verify; fall back to the native setter if the framework fought back
if (!text.equals(input.getDomProperty("value"))) {
((JavascriptExecutor) driver).executeScript("""
const el = arguments[0];
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
""", input, text);
}
}
import platform
def replace_text(driver, element, text):
element.click()
modifier = Keys.COMMAND if platform.system() == "Darwin" else Keys.CONTROL
element.send_keys(modifier + "a", Keys.DELETE)
element.send_keys(text)
if element.get_property("value") != text:
driver.execute_script("""
const el = arguments[0];
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
""", element, text)
async function replaceText(driver, input, text) {
await input.click();
const modifier = process.platform === 'darwin' ? Key.COMMAND : Key.CONTROL;
await input.sendKeys(Key.chord(modifier, 'a'), Key.DELETE);
await input.sendKeys(text);
if ((await input.getProperty('value')) !== text) {
await driver.executeScript(`
const el = arguments[0];
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
`, input, text);
}
}
public static void ReplaceText(IWebDriver driver, IWebElement input, string text)
{
input.Click();
var modifier = OperatingSystem.IsMacOS() ? Keys.Command : Keys.Control;
input.SendKeys(modifier + "a" + Keys.Delete);
input.SendKeys(text);
if (input.GetDomProperty("value") != text)
{
((IJavaScriptExecutor)driver).ExecuteScript(@"
const el = arguments[0];
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));", input, text);
}
}

Why It Works

Select-all plus Delete plus typing generates the same keydown, beforeinput, input sequence a user generates, so the framework’s onChange runs for every character and state stays in sync. The verification step catches the rare widget that intercepts keyboard shortcuts, and the setter fallback updates state through the property React and friends observe.

Gotchas

  • On a Grid the browser OS decides the modifier key, not the runner; read platformName from capabilities if runner and browser differ.
  • Keys.chord is Java-only; other bindings concatenate the modifier and the letter.
  • Inputs with masks (phone numbers, currency) may reformat while typing; assert on the final formatted value rather than the raw text you sent.

Learn the theory