Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/l-xiaoshen/handstage/llms.txt

Use this file to discover all available pages before exploring further.

Locator is a lazy element handle scoped to a specific Frame. It resolves its selector fresh on every action, so you never deal with stale element references. Locators are created from page.locator(selector) or from frameLocator.locator(selector) for cross-frame access. CSS selectors, XPath expressions, and text selectors are all supported. The type is detected automatically from the string prefix. XPath is detected when the string starts with / or (. Use an explicit xpath=, css=, or text= prefix to override auto-detection.
// CSS selector
const btn = page.locator("button[type=submit]")

// XPath
const heading = page.locator("//h1[@class='title']")

Pointer actions

locator.click

Scroll the element into view, resolve its bounding box, and dispatch a mouse press + release at its visual center.
await page.locator("button.submit").click()

// Right-click
await page.locator("#context-target").click({ button: "right" })

// Double-click
await page.locator("#item").click({ clickCount: 2 })
options.button
"left" | "right" | "middle"
default:"\"left\""
Which mouse button to use.
options.clickCount
number
default:"1"
Number of clicks to dispatch.
Returns Promise<void> Throws ElementNotVisibleError if the element has no box model (is not rendered). Throws HandstagesElementNotFoundError if the selector matches nothing.

locator.hover

Move the mouse cursor to the element’s visual center without clicking.
await page.locator("nav .dropdown-trigger").hover()
Returns Promise<void>

Input actions

locator.fill

Fill an <input>, <textarea>, or contenteditable element with a value. Uses a native value setter where possible; falls back to typed input for elements that require it.
await page.locator("#email").fill("user@example.com")
await page.locator("textarea[name=bio]").fill("Hello, world!")
value
string
required
The text to set as the element’s value.
Returns Promise<void>

locator.type

Type text into a focused element character by character. Focuses the element first, then uses Input.insertText (fast, no delay) or synthesizes keyDown/keyUp events per character when a delay is specified.
await page.locator("#search").type("hello world")

// With delay between keystrokes (simulates human typing)
await page.locator("#search").type("hello world", { delay: 50 })
text
string
required
The text to type into the element.
options.delay
number
Milliseconds to wait between each keystroke. When omitted, Input.insertText is used for efficiency.
Returns Promise<void>

locator.selectOption

Select one or more options on a <select> element by value. Returns the values that were actually selected.
const selected = await page.locator("select#country").selectOption("US")
const multi = await page.locator("select#tags").selectOption(["a", "b"])
values
string | string[]
required
One or more option values to select.
Returns Promise<string[]> — the values selected after the operation.

locator.setInputFiles

Set files on an <input type="file"> element. Accepts file paths (local connections) or in-memory payload objects (all connection types).
// File path (local browser only)
await page.locator("input[type=file]").setInputFiles("/path/to/file.pdf")

// In-memory payload (works for remote browsers too)
await page.locator("input[type=file]").setInputFiles({
  name: "report.csv",
  mimeType: "text/csv",
  buffer: Buffer.from("col1,col2\nval1,val2"),
})

// Multiple files
await page.locator("input[type=file]").setInputFiles([
  "/path/to/a.png",
  { name: "b.png", mimeType: "image/png", buffer: imageBuffer },
])

// Clear the selection
await page.locator("input[type=file]").setInputFiles([])
files
SetInputFilesArgument
required
A single file path, an array of file paths, a single SetInputFilePayload, or an array of payloads. Pass an empty array to clear the selection.
Returns Promise<void> Throws HandstagesInvalidArgumentError if the target element is not an <input type="file">, or if a remote upload payload exceeds 50 MB.

SetInputFilesArgument type

type SetInputFilesArgument =
  | string
  | string[]
  | SetInputFilePayload
  | SetInputFilePayload[]

SetInputFilePayload type

name
string
required
File name including extension (e.g., "report.csv").
mimeType
string
MIME type of the file (e.g., "text/csv", "image/png"). Optional; the browser may infer from the name.
buffer
ArrayBuffer | Uint8Array | Buffer | string
required
The file content. Strings are interpreted as base64-encoded data.
lastModified
number
Unix timestamp (ms) for the file’s last-modified date. Defaults to the current time when omitted.

Reading element state

locator.textContent

Return the element’s textContent — the raw concatenated text of all descendant nodes.
const raw = await page.locator(".product-title").textContent()
Returns Promise<string>

locator.innerText

Return the element’s innerText — the layout-aware, visible text, respecting CSS display and visibility.
const visible = await page.locator("p.description").innerText()
Returns Promise<string>

locator.innerHtml

Return the element’s innerHTML string.
const html = await page.locator(".card").innerHtml()
Returns Promise<string>

locator.inputValue

Return the current value of an <input>, <textarea>, <select>, or contenteditable element.
const value = await page.locator("input#email").inputValue()
Returns Promise<string>

locator.isVisible

Return true if the element is attached to the DOM and visible (rough heuristic — not a strict layout check).
const visible = await page.locator(".modal").isVisible()
Returns Promise<boolean>

locator.isChecked

Return true if the element is a checked <input type="checkbox"> or <input type="radio">. Also considers aria-checked for ARIA widgets.
const checked = await page.locator("input#agree").isChecked()
Returns Promise<boolean>

locator.count

Return the number of DOM nodes matched by the selector.
const n = await page.locator("li.item").count()
Returns Promise<number>

locator.centroid

Return the center point of the element’s bounding box in the owning frame’s viewport coordinate space, in CSS pixels.
const { x, y } = await page.locator("button.submit").centroid()
Returns Promise<{ x: number; y: number }> Throws ElementNotVisibleError if the element has no box model.

Locator refinement

locator.nth

Return a new locator narrowed to the element at the given zero-based index among all matches. Useful when a selector matches multiple elements.
const third = page.locator("li.item").nth(2)
await third.click()
index
number
required
Zero-based index. Must be a non-negative integer.
Returns Locator

locator.first

Shorthand for locator.nth(0). Returns a locator scoped to the first match.
const first = page.locator("li.item").first()
Returns Locator

Frame access

locator.getFrame

Return the Frame that owns this locator. Useful for performing frame-level operations when you already have a locator reference.
const frame = page.locator("iframe").getFrame()
Returns Frame

Visual utilities

locator.highlight

Highlight the element’s bounding box using the CDP Overlay domain. Shows a semi-transparent overlay briefly, then hides it. Useful for visual debugging.
await page.locator("button.submit").highlight()

// Custom duration and colors
await page.locator("button.submit").highlight({
  durationMs: 1500,
  borderColor: { r: 0, g: 128, b: 255, a: 0.9 },
  contentColor: { r: 0, g: 128, b: 255, a: 0.2 },
})
options.durationMs
number
default:"800"
How long to show the highlight, in milliseconds.
options.borderColor
{ r: number; g: number; b: number; a?: number }
RGBA color for the border overlay. Defaults to red with 90% opacity.
options.contentColor
{ r: number; g: number; b: number; a?: number }
RGBA color for the content fill overlay. Defaults to yellow with 20% opacity.
Returns Promise<void>

locator.scrollTo

Scroll the element vertically to a given percentage of its scroll height. For <html> or <body>, scrolls the window instead.
// Scroll element to 50%
await page.locator(".feed").scrollTo(50)

// Scroll to the bottom
await page.locator(".feed").scrollTo(100)
percent
number | string
required
Target scroll position as a percentage (0–100).
Returns Promise<void>

locator.sendClickEvent

Dispatch a DOM click MouseEvent directly on the element without synthesizing real pointer input. Useful for elements that use a click event handler but don’t need hit-testing (for example, hidden elements that are programmatically clickable).
await page.locator("button#confirm").sendClickEvent()

// Custom event options
await page.locator("#custom-widget").sendClickEvent({ bubbles: true, detail: 2 })
options.bubbles
boolean
default:"true"
Whether the event bubbles up through the DOM.
options.cancelable
boolean
default:"true"
Whether the event is cancelable.
options.composed
boolean
default:"true"
Whether the event propagates across shadow DOM boundaries.
options.detail
number
default:"1"
Click count detail on the MouseEvent.
Returns Promise<void>

locator.backendNodeId

Return the CDP DOM.BackendNodeId for the resolved element. Useful for identity comparisons at the CDP level without needing to hold a live remote object.
const nodeId = await page.locator("button.submit").backendNodeId()
Returns Promise<number>

Build docs developers (and LLMs) love