Skip to main content
SeleniumDecoded

Set a Date in a Date Picker

Type into the input when allowed, set the value directly when it is read-only, or drive the calendar widget when nothing else works.

Medium Verified against Selenium 4.48.0

Problem

Date pickers come in three kinds: a native <input type="date">, a text input with a calendar popup, and a read-only field that only accepts clicks in a calendar. Each needs a different technique, and clicking through months is slow and fragile.

Solution

Prefer typing. Fall back to setting the value and dispatching the events the framework listens for. Drive the calendar only for widgets that ignore both.

Three strategies in order of preference
Selenium 3 & 4 Medium
WebElement date = driver.findElement(By.id("delivery-date"));
JavascriptExecutor js = (JavascriptExecutor) driver;
// 1. Native input[type=date]: type in the browser's locale format (Chrome: mmddyyyy keystrokes)
// or set the ISO value directly, which is what the input stores.
js.executeScript("arguments[0].value = '2026-10-15'; arguments[0].dispatchEvent(new Event('change', {bubbles: true}));", date);
// 2. Text input with popup: clear, type, press Escape to close the popup
date.clear();
date.sendKeys("15/10/2026", Keys.ESCAPE);
// 3. Read-only input driven by a React/Vue calendar: set the value through the framework's setter
js.executeScript("""
const el = arguments[0];
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
setter.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
""", date, "15/10/2026");
date = driver.find_element(By.ID, "delivery-date")
# 1. Native input[type=date]: set the ISO value it stores
driver.execute_script(
"arguments[0].value = '2026-10-15'; arguments[0].dispatchEvent(new Event('change', {bubbles: true}));", date)
# 2. Text input with popup
date.clear()
date.send_keys("15/10/2026", Keys.ESCAPE)
# 3. Read-only input driven by React/Vue: use the native setter so the framework notices
driver.execute_script("""
const el = arguments[0];
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
setter.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
""", date, "15/10/2026")
const date = await driver.findElement(By.id('delivery-date'));
// 1. Native
await driver.executeScript(
"arguments[0].value = '2026-10-15'; arguments[0].dispatchEvent(new Event('change', {bubbles: true}));", date);
// 2. Text input with popup
await date.clear();
await date.sendKeys('15/10/2026', Key.ESCAPE);
// 3. Framework-controlled read-only input
await driver.executeScript(`
const el = arguments[0];
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
setter.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
`, date, '15/10/2026');
var date = driver.FindElement(By.Id("delivery-date"));
var js = (IJavaScriptExecutor)driver;
// 1. Native
js.ExecuteScript("arguments[0].value = '2026-10-15'; arguments[0].dispatchEvent(new Event('change', {bubbles: true}));", date);
// 2. Text input with popup
date.Clear();
date.SendKeys("15/10/2026" + Keys.Escape);
// 3. Framework-controlled read-only input
js.ExecuteScript(@"
const el = arguments[0];
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
setter.call(el, arguments[1]);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));", date, "15/10/2026");

Why It Works

Typing exercises the real input path. Setting .value skips it, so you must dispatch input and change yourself. React in particular tracks the value through the native property setter; assigning el.value directly is swallowed, which is why strategy 3 calls the prototype setter.

Gotchas

  • Native date inputs store ISO (yyyy-mm-dd) regardless of display format; typing uses the locale format.
  • Strategy 3 bypasses the calendar’s own validation (min/max dates, disabled days). Assert the app accepted the value afterwards.
  • Only drive the calendar (clicking month arrows and day cells) when the picker has business logic in those clicks, and then compute the number of “next month” clicks from the current date rather than hard-coding it.

Learn the theory