Skip to content

Fill on <input type="date"> and <input type="time"> confirmed not working #1249

@brennanmceachran

Description

@brennanmceachran

Before submitting an issue, please:

Environment Information

Stagehand:

  • Language/SDK: TypeScript
  • Stagehand version: 3.0.1
  • Chrome: 144

Issue Description

Locator.fill() (and act({ method: 'fill' })) on native HTML5 date/time inputs resolve without error, but an immediate locator.inputValue() reads back an empty string. Setting the value via the native setter inside the page context (evaluate) and dispatching input/change events succeeds consistently.

Steps to Reproduce

  1. Initialize Stagehand locally (no LLM needed).
  2. Navigate to a data: URL containing a native <input type="date"> (and optionally <input type="time">).
  3. Call page.locator(xpath).fill('2025-11-15'); immediately call locator.inputValue() — observe empty string.
  4. Call stagehand.act({ selector, method: 'fill', arguments: [...] }); immediately call locator.inputValue() — observe empty string.
  5. Call page.evaluate() to set via native setter and dispatch input/change; immediately call locator.inputValue() — observe the expected value.

Minimal Reproduction Code

Image
import { Stagehand } from "@browserbasehq/stagehand";

function htmlDemo() {
return `<!doctype html>

  <meta charset="utf-8" />
  <title>Stagehand date/time fill demo</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 24px; }
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
    .card { border: 1px solid #ddd; border-radius: 8px; padding: 16px; }
    .card h2 { margin: 0 0 8px; font-size: 16px; }
    .row { margin: 8px 0; display: flex; gap: 8px; align-items: center; }
    label { display: inline-flex; align-items: center; gap: 6px; }
    input { padding: 6px 8px; border: 1px solid #ccc; border-radius: 6px; }
    .status { margin-top: 8px; font-size: 12px; color: #555; }
    .ok input { border-color: #16a34a; box-shadow: 0 0 0 2px #16a34a22; }
    .ok .status { color: #16a34a; }
    .fail input { border-color: #dc2626; box-shadow: 0 0 0 2px #dc262622; }
    .fail .status { color: #dc2626; }
    .hint { color: #666; font-size: 12px; margin-bottom: 8px; }
  </style>
  <h1>Stagehand native date/time fill — broken vs working</h1>
  <p class="hint">Demonstrates two broken approaches (locator.fill, act(fill)) and one working approach (evaluate with native setter).</p>
  <div class="grid">
    <div class="card" id="card-loc">
      <h2>Locator.fill()</h2>
      <div class="row"><label>Date <input id="d_loc" type="date"></label></div>
      <div class="row"><label>Time <input id="t_loc" type="time"></label></div>
      <div class="status" id="status_loc">Pending…</div>
    </div>
    <div class="card" id="card-act">
      <h2>act({ method: 'fill' })</h2>
      <div class="row"><label>Date <input id="d_act" type="date"></label></div>
      <div class="row"><label>Time <input id="t_act" type="time"></label></div>
      <div class="status" id="status_act">Pending…</div>
    </div>
    <div class="card" id="card-eval">
      <h2>Evaluate (native setter)</h2>
      <div class="row"><label>Date <input id="d_eval" type="date"></label></div>
      <div class="row"><label>Time <input id="t_eval" type="time"></label></div>
      <div class="status" id="status_eval">Pending…</div>
    </div>
  </div>`;
}

async function setViaEvaluate(page: any, selector: string, val: string) {
await page.evaluate(({ xp, val }) => {
const doc = (globalThis as any).document;
const xpExpr = xp.startsWith("xpath=") ? xp.slice(6) : xp;
const res = doc.evaluate(xpExpr, doc, null, 9, null);
const el = res.singleNodeValue as any;
if (!el || String(el.tagName || "").toUpperCase() !== "INPUT") return;
const desc = (globalThis as any).HTMLInputElement?.prototype &&
Object.getOwnPropertyDescriptor((globalThis as any).HTMLInputElement.prototype, "value");
if (desc && typeof desc.set === "function") desc.set.call(el, val);
else el.value = String(val);
const E = (globalThis as any).Event;
el.dispatchEvent(new E("input", { bubbles: true }));
el.dispatchEvent(new E("change", { bubbles: true }));
}, { xp: selector, val });
}

async function markCard(page: any, cardId: string, dateId: string, timeId: string, readDate: string, readTime: string, expectDate: string, expectTime: string) {
await page.evaluate(({ cardId, dateId, timeId, readDate, readTime, expectDate, expectTime }) => {
const doc = (globalThis as any).document;
const card = doc.getElementById(cardId);
const d = doc.getElementById(dateId) as any;
const t = doc.getElementById(timeId) as any;
const status = doc.getElementById('status\_' + cardId.split('-')[1]);
const ok = readDate === expectDate && readTime === expectTime;
if (card) card.classList.remove('ok','fail');
if (card) card.classList.add(ok ? 'ok' : 'fail');
if (status) status.textContent = `Date=${JSON.stringify(readDate)} Time=${JSON.stringify(readTime)} ${ok ? '✓ OK' : '✗ FAIL'}`;
// Also reflect final values in the inputs for visibility
if (d) d.value = readDate;
if (t) t.value = readTime;
}, { cardId, dateId, timeId, readDate, readTime, expectDate, expectTime });
}

async function main() {
const sh = new Stagehand({ env: "LOCAL", verbose: 1, localBrowserLaunchOptions: { headless: false } });
await sh.init();
const page = sh.context.pages()[0];
if (!page) throw new Error("no page");

await page.goto(`data:text/html,${encodeURIComponent(htmlDemo())}`);
await page.waitForLoadState("domcontentloaded");

const date = "2025-11-15";
const time = "10:00";

// Locator.fill() card
await page.locator('xpath=//_[@id="d_loc"]').fill(date);
await page.locator('xpath=//_[@id="t_loc"]').fill(time);
const dLoc = await page.locator('xpath=//_[@id="d_loc"]').inputValue();
const tLoc = await page.locator('xpath=//_[@id="t_loc"]').inputValue();
await markCard(page, 'card-loc', 'd_loc', 't_loc', dLoc, tLoc, date, time);

// act({ method: 'fill' }) card
await sh.act({ selector: 'xpath=//_[@id="d_act"]', description: 'date via act', method: 'fill', arguments: [date] });
await sh.act({ selector: 'xpath=//_[@id="t_act"]', description: 'time via act', method: 'fill', arguments: [time] });
const dAct = await page.locator('xpath=//_[@id="d_act"]').inputValue();
const tAct = await page.locator('xpath=//_[@id="t_act"]').inputValue();
await markCard(page, 'card-act', 'd_act', 't_act', dAct, tAct, date, time);

// Evaluate (native setter) card
await setViaEvaluate(page, 'xpath=//_[@id="d_eval"]', date);
await setViaEvaluate(page, 'xpath=//_[@id="t_eval"]', time);
const dEval = await page.locator('xpath=//_[@id="d_eval"]').inputValue();
const tEval = await page.locator('xpath=//_[@id="t_eval"]').inputValue();
await markCard(page, 'card-eval', 'd_eval', 't_eval', dEval, tEval, date, time);

console.log("\nOpen browser to see three cards: two broken (red), one working (green). Close tab to finish.");
}

main().catch((err) => { console.error(err); process.exit(1); });

Error Messages / Log trace


============================================================
BROKEN PATHS (expected to be flaky or empty)
============================================================
Date: locator.fill → inputValue (expected empty)

[2025-11-08T06:25:12.978Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="d"]
    ctxId: 2
[2025-11-08T06:25:12.984Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="d"]
    ctxId: 2
[2025-11-08T06:25:12.998Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="d"]
    ctxId: 2
after fill: ""

Date: act(fill) → inputValue (expected empty)

[2025-11-08T06:25:13.025Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="d"]
    ctxId: 2
after act(fill): ""

Time: locator.fill → inputValue (expected empty)

[2025-11-08T06:25:13.028Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="t"]
    ctxId: 2
[2025-11-08T06:25:13.031Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="t"]
    ctxId: 2
[2025-11-08T06:25:13.035Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="t"]
    ctxId: 2
after fill: ""

Time: act(fill) → inputValue (expected empty)

[2025-11-08T06:25:13.058Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="t"]
    ctxId: 2
after act(fill): ""

============================================================
WORKING PATHS (expected to succeed)
============================================================
Date: evaluate(native setter) → inputValue (expected "2025-11-15")

[2025-11-08T06:25:13.063Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="d"]
    ctxId: 2
after evaluate: "2025-11-15"

Time: evaluate(native setter) → inputValue (expected "10:00")

[2025-11-08T06:25:13.068Z] DEBUG: xpath main-world
    frameId: 55A9F6AEBE837C4D00A34C645D4510D3
    xp: //*[@id="t"]
    ctxId: 2
after evaluate: "10:00"

Done. Close the browser to finish.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions