JavaScript API Reference
Overview
Section titled “Overview”The @crowecawcaw/xa11y package provides cross-platform accessibility queries
and actions for Node.js. All methods that touch the accessibility tree
are asynchronous — they run on the napi tokio worker pool so the Node
event loop stays responsive.
import { App } from '@crowecawcaw/xa11y';
const app = await App.byName('Safari');await app.locator('button[name="OK"]').press();type CheckedState
Section titled “type CheckedState”Checked state of a toggleable element.
type CheckedState = 'on' | 'off' | 'mixed';type EventTypeName
Section titled “type EventTypeName”Accessibility event type names, normalised across platforms.
type EventTypeName = | 'focusChanged' | 'valueChanged' | 'nameChanged' | 'stateChanged' | 'structureChanged' | 'windowOpened' | 'windowClosed' | 'windowActivated' | 'windowDeactivated' | 'selectionChanged' | 'menuOpened' | 'menuClosed' | 'textChanged' | 'announcement';type MouseButtonName
Section titled “type MouseButtonName”Mouse buttons accepted by the input-simulation API.
type MouseButtonName = 'left' | 'right' | 'middle';type AnchorName
Section titled “type AnchorName”Named anchor points inside an element’s bounds.
type AnchorName = | 'center' | 'top_left' | 'top_right' | 'bottom_left' | 'bottom_right';type OmissionReasonName
Section titled “type OmissionReasonName”Why an annotated element is not in the image. Spelled as in Python.
type OmissionReasonName = 'no_bounds' | 'zero_area' | 'outside_capture';type ShellSurfaceKindName
Section titled “type ShellSurfaceKindName”Kinds of OS shell surface, spelled as in Python, the CLI and MCP.
type ShellSurfaceKindName = | 'menu_bar' | 'status_items' | 'taskbar' | 'panel' | 'dock' | 'desktop' | 'flyout' | 'unknown';type NativeSubscription
Section titled “type NativeSubscription”type NativeSubscription = _NativeSubscription;type TestActionProbe
Section titled “type TestActionProbe”type TestActionProbe = _TestActionProbe
/** * A running application — the entry point for accessibility queries. * * Construct via {@link App.byName}, {@link App.byPid}, or {@link App.list}. * An `App` is **not** an `Element` — it represents the application as a * whole and provides {@link App.locator} to search its accessibility tree. */export declare class App { /** * Find an application by exact name. * * Polls the accessibility API until the app appears or * `options.timeout` (ms) elapses. When omitted, the process-wide * default applies — 5 seconds unless overridden via * `setDefaultTimeout()` / `XA11Y_DEFAULT_TIMEOUT`. Pass `{ timeout: 0 }` * for a single attempt with no waiting. Only "not found" errors trigger * a retry; permission errors and the like fail fast. * * Rejects with `PermissionDeniedError` if accessibility is not enabled, * or `SelectorNotMatchedError` if no matching app is found. */ static byName(name: string, options?: AppLookupOptions | undefined | null): Promise<App> /** * Find an application by process ID. * * See {@link App.byName} for the `options.timeout` behaviour. */ static byPid(pid: number, options?: AppLookupOptions | undefined | null): Promise<App> /** * Resolve the application that currently holds the system foreground. * * Uses the platform's direct foreground query rather than enumerating and * tagging by pid. The result is the foreground *process*'s `Application` * node — one per process on every platform — not the exact window holding * the focus; on Windows that is the synthesized node of the foreground * process (the modal case, issues #304/#305), and this stays reliable * when an app shows a modal dialog. To reach the exact foreground window, * call `windows()` and pick the entry reporting `active`. Polls while * nothing holds focus; see {@link App.byName} for the `options.timeout` * behaviour. The returned app has `isForeground === true`. */ static foreground(options?: AppLookupOptions | undefined | null): Promise<App> /** List all running applications with an accessibility tree. */ static list(): Promise<App[]> /** The application's human-readable name (e.g. `"Safari"`). */ get name(): string /** * The application's process ID, or `null` if the platform does not * expose one for this app. */ get pid(): number | null /** * Whether this application is the foreground application. * * Named `isForeground` because "focused" is reserved for element-level * keyboard focus (`Element.focused`) elsewhere in the API; this is the * foreground-*application* flag. Populated for apps obtained via * {@link App.list}. A point-in-time snapshot taken when the `App` was * resolved. * * Tagging is window-precise. On Windows apps surface as one synthesized * `Application` node per process, so a pid match there is unambiguous; on * Linux the AT-SPI registry can surface several entries for one pid, and * only the entry reporting the window-level `active` flag gets * `isForeground`. Use {@link App.foreground} to resolve the foreground * application directly, then pick the exact foreground window from its * `windows()`. */ get isForeground(): boolean /** * Whether this application is the foreground application. * * @deprecated Use {@link App.isForeground}. "focused" refers to element * keyboard focus elsewhere in the API. */ get focused(): boolean /** * Create a `Locator` scoped to this application's accessibility tree. * * The locator re-resolves `selector` on every operation, so it always * targets the current UI state — see the `Locator` class for the full * API. */ locator(selector: string): Locator /** Get direct children (typically windows) of this application. */ children(): Promise<Element[]> /** * List the top-level windows of this application. * * Each call queries the provider; results are not cached. The windows * are the application's top-level windows with role `window` or * `dialog`, in enumeration order. On Windows the application entry is a * synthesized process node whose children are the process's top-level * windows (main window plus modal dialogs). On Linux the answer is * process-complete: `App::windows_with` merges the filtered children of * every same-pid AT-SPI Application entry (an app that registers several * entries reports its whole process), so the results need not be the * direct children of this node and no single z-order spans them. * Calling `windows` on a non-application element fails with * `ActionNotSupportedError`. */ windows(): Promise<Element[]> /** * Get an `Element` handle for the application root. * * Useful for invoking Element-level methods (`children()`, `parent()`, * etc.) without going through a locator. Synchronous — the App already * holds the application's accessibility data. */ asElement(): Element /** Subscribe to accessibility events from this application. */ subscribe(): Promise<_NativeSubscription> /** * Capture this application's accessibility tree as a recursive snapshot, * rooted at the application element. * * `maxDepth` limits traversal depth: `0` = only the application node, * `1` = application + direct children (typically windows), and so on. * Omit for the full subtree. */ tree(maxDepth?: number | null): Promise<TreeNode> /** * Render this application's accessibility tree as an indented string. * * Returns the string without printing it. The primary inspection helper * — call `console.log(await app.dump())` to discover the role and name * of every element in the app before writing selectors. * * For the same output from the shell, use `xa11y tree --app NAME`. */ dump(maxDepth?: number | null): Promise<string>}
/** * A snapshot of a node in the accessibility tree. * * Property getters (`role`, `name`, `value`, state flags, etc.) are * synchronous — they read the snapshot data captured when the element * was fetched. Navigation methods (`children()`, `parent()`) are async * and re-query the provider on every call, so you always see the latest * tree state. * * Elements are cheap to pass around; they share the provider handle * internally. */export declare class Element { /** The element's role, as a snake_case string (e.g. `"button"`, `"check_box"`). */ get role(): string /** Human-readable name (title, label, or ARIA name). */ get name(): string | null /** * Current value — text content for editable fields, stringified slider * position, etc. For numeric controls, prefer `numericValue`. */ get value(): string | null /** Supplementary description (tooltip text, ARIA description). */ get description(): string | null /** Numeric value for sliders, spin buttons, and progress indicators. */ get numericValue(): number | null /** Minimum numeric value for bounded controls (slider, spin button). */ get minValue(): number | null /** Maximum numeric value for bounded controls (slider, spin button). */ get maxValue(): number | null /** * Platform-assigned identifier that is stable across queries for the * same element. Not available on every platform / every widget. */ get stableId(): string | null /** Process ID of the owning application. */ get pid(): number | null /** * Names of actions the element advertises (e.g. `["press", "focus"]`). * Use `Locator.performAction(name)` to invoke a custom action, or the * named convenience methods (`press`, `toggle`, etc.) for the common * ones. */ get actions(): Array<string> /** * Screen-coordinate bounding rectangle, or `null` for virtual / * off-screen elements that do not have a physical position. */ get bounds(): Rect | null /** * Platform-specific raw data attached to this element, as a plain JS * object. Keys are provider-defined (e.g. `ax_role`/`ax_subrole` on macOS, * `uia_control_type` on Windows). Values are JSON-compatible — strings, * numbers, booleans, arrays, nested objects. Intended for debugging and * platform-specific queries. */ get raw(): Record<string, unknown> /** `true` if the element is interactive (not greyed out or disabled). */ get enabled(): boolean /** * `true` if the element is currently rendered on screen (not hidden, * not clipped off the viewport). */ get visible(): boolean /** `true` if the element currently has keyboard focus. */ get focused(): boolean /** * `true` if the element is the active (foreground) window — the window * that currently receives the user's input. Meaningful for window-like * elements (windows, dialogs); `false` elsewhere. Distinct from * `focused`, which is element-level keyboard focus. */ get active(): boolean /** * Tri-state checked value for checkboxes, toggle buttons, and menu items: * `"on"`, `"off"`, `"mixed"`, or `null` if the element is not toggleable. */ get checked(): CheckedState | null /** `true` if the element is selected (list item, tab, row). */ get selected(): boolean /** * `true` / `false` for expandable elements (disclosures, menus, tree * items); `null` if the element is not expandable. */ get expanded(): boolean | null /** * `true` if the element accepts text editing (text field, text area, * rich-text region). */ get editable(): boolean /** * `true` if the element can receive keyboard focus (distinct from * `focused`, which reports the current state). */ get focusable(): boolean /** * `true` if the element is a modal dialog that blocks interaction with * the rest of the app. */ get modal(): boolean /** `true` for form fields that are marked required. */ get required(): boolean /** * `true` if the element is loading or otherwise indicating a busy * state (progress indicator, spinner region). */ get busy(): boolean /** * Whether the window is minimized, or `null` if unknown / not a window. * A platform that cannot report the state says `null` rather than * guessing `false`. */ get minimized(): boolean | null /** Whether the window is maximized, or `null` if unknown / not a window. */ get maximized(): boolean | null /** Whether the window is fullscreen, or `null` if unknown / not a window. */ get fullscreen(): boolean | null /** Get direct children (lazy — each call re-queries the provider). */ children(): Promise<Element[]> /** Get the parent element, or `null` if this is the root. */ parent(): Promise<Element | null> /** Subscribe to accessibility events for this element (typically an app). */ subscribe(): Promise<_NativeSubscription> /** * Capture the subtree rooted at this element as a recursive snapshot. * * `maxDepth` limits traversal depth: `0` = only this node (no children), * `1` = node + direct children, and so on. Omit for the full subtree. */ tree(maxDepth?: number | null): Promise<TreeNode> /** * Render the subtree rooted at this element as an indented string. * * Returns the string without printing it. Same depth semantics as `tree()`. */ dump(maxDepth?: number | null): Promise<string> /** * Click / invoke this element. Acts on the captured snapshot — does * not re-resolve. */ press(): Promise<void> /** Move keyboard focus to this element. Acts on the captured snapshot. */ focus(): Promise<void> /** * Remove keyboard focus from this element. Acts on the captured * snapshot. * * Not supported on Linux or Windows — on those platforms this rejects * with `ActionNotSupportedError`. */ blur(): Promise<void> /** * Toggle a two- or three-state control (checkbox, switch, toggle * button). Acts on the captured snapshot. */ toggle(): Promise<void> /** * Expand a disclosure, menu, or tree item. Acts on the captured * snapshot. */ expand(): Promise<void> /** * Collapse a disclosure, menu, or tree item. Acts on the captured * snapshot. */ collapse(): Promise<void> /** * Select this element (list item, tab, row). Acts on the captured * snapshot. */ select(): Promise<void> /** Open this element's context menu. Acts on the captured snapshot. */ showMenu(): Promise<void> /** * Scroll this element into the visible area. Acts on the captured * snapshot. * * No-op on macOS — the macOS accessibility API has no equivalent. Uses * `Component.ScrollTo` on Linux and `ScrollItemPattern` on Windows. */ scrollIntoView(): Promise<void> /** * Increment a numeric value (slider, spin button) by its platform step. * Acts on the captured snapshot. */ increment(): Promise<void> /** * Decrement a numeric value (slider, spin button) by its platform step. * Acts on the captured snapshot. */ decrement(): Promise<void> /** * Set the text value of this element. Replaces the entire value rather * than inserting at the caret — use `typeText` for insertion. Acts on * the captured snapshot. */ setValue(value: string): Promise<void> /** * Set the numeric value of this element (slider, spin button). Acts on * the captured snapshot. */ setNumericValue(value: number): Promise<void> /** * Type `text` at the current caret position. Acts on the captured * snapshot. * * Uses the platform accessibility API — never simulates keyboard events. * For synthesised keystrokes (global shortcuts, drag gestures), use the * `InputSim` surface instead. */ typeText(text: string): Promise<void> /** * Select the text range from `start` to `end` (0-based character * offsets). Rejects with `InvalidActionDataError` if `start > end`. * Acts on the captured snapshot. */ selectText(start: number, end: number): Promise<void> /** * Perform a custom action by its snake_case name. Acts on the captured * snapshot. * * Use this for actions the element advertises in its `actions` list * that don't have a dedicated method. Rejects with * `ActionNotSupportedError` if the element does not advertise `action`. */ performAction(action: string): Promise<void> /** Activate this window: bring it to the foreground and give it focus. */ activate(): Promise<void> /** Minimize this window. */ minimize(): Promise<void> /** Maximize this window. */ maximize(): Promise<void> /** Restore this window to its normal state (from minimized/maximized). */ restore(): Promise<void> /** Close this window. */ close(): Promise<void> /** * Move this window to the given logical screen coordinates (top-left * origin, the same space as `bounds`). Rejects with * `InvalidActionDataError` unless both coordinates are finite whole * numbers in the 32-bit signed range. */ moveTo(x: number, y: number): Promise<void> /** * Resize this window to the given logical width and height. Rejects * with `InvalidActionDataError` unless both dimensions are positive * whole numbers (and no larger than the 32-bit unsigned range). */ resizeTo(width: number, height: number): Promise<void>}
/** * An accessibility event delivered to a `Subscription`. * * Events are emitted from the source application — focus changes, value * edits, window lifecycle, structural updates. Attach a listener via * `subscription.on(type, handler)` or await one with * `subscription.waitForEvent(type, opts)`. */export declare class Event { /** Event kind, as a camelCase string (e.g. `"focusChanged"`, `"valueChanged"`). */ get type(): EventTypeName /** * For `stateChanged` events: the flag that changed (e.g. `"checked"`, `"busy"`). * `null` for all other event kinds. */ get stateFlag(): string | null /** * For `stateChanged` events: the new boolean value of the flag. * `null` for all other event kinds. */ get stateValue(): boolean | null /** Name of the application that emitted this event. */ get appName(): string /** Process ID of the application that emitted this event. */ get appPid(): number /** Snapshot of the element that triggered the event, if available. */ get target(): Element | null}
/** * Synthesises OS-level pointer and keyboard events. * * Constructed via the module-level `inputSim()` function. Targets are * either an `[x, y]` tuple in logical screen coordinates (same space as * `Element.bounds`), or an `Element` (centred on its bounds). Each backend * converts to physical device pixels at the OS boundary. Key values are * strings: printable characters are literal * (`"a"`, `"7"`, `";"`); named keys use their Pascal name (`"Enter"`, * `"ArrowUp"`, `"F5"`); modifiers are `"Shift"`, `"Ctrl"`, `"Alt"`, * `"Meta"`. * * Input simulation is distinct from the accessibility action layer — * prefer `Locator.press` / `Locator.typeText` when the target exposes * the semantic action. Use `InputSim` for gestures with no a11y * equivalent (drag-and-drop, scroll wheels, global shortcuts). * * Methods return `Promise<void>` — the underlying OS input APIs are * synchronous but can block briefly, so they run on the napi worker pool. */export declare class InputSim { /** * Click at `target`. * * `options` is core's `ClickOptions`: `button` selects the mouse button, * `count` repeats the click (`2` = double-click), `held` lists keys held * down for the duration, and `anchor` picks the point inside an * `Element`'s bounds. With no options this is a single left click at the * element's centre. */ click(target: Array<number> | Element, options?: ClickOptions | undefined | null): Promise<void> /** Left double-click at `target`. */ doubleClick(target: Array<number> | Element): Promise<void> /** Right-click at `target`. */ rightClick(target: Array<number> | Element): Promise<void> /** Move the pointer to `target` without pressing any button. */ moveTo(target: Array<number> | Element): Promise<void> /** * Press a mouse button at the current pointer location, without * releasing it. Pair with `mouseUp()`; for a whole click use `click()`. * * Takes no target: the button is pressed wherever the pointer already * is, matching the OS primitive. Call `moveTo()` first to position it. */ mouseDown(button?: MouseButtonName | undefined | null): Promise<void> /** Release a mouse button at the current pointer location. */ mouseUp(button?: MouseButtonName | undefined | null): Promise<void> /** * Drag from `start` to `end`. * * `options` is core's `DragOptions`: `button` selects the button held * during the drag, `held` lists keys held for its duration, and * `duration` is the total drag time in milliseconds (default `150`). */ drag(start: Array<number> | Element, end: Array<number> | Element, options?: DragOptions | undefined | null): Promise<void> /** * Scroll at `target`. `dx` positive → right, `dy` positive → content * scrolls down. Defaults: `0`, `0` (a no-op). */ scroll(target: Array<number> | Element, dx?: number | undefined | null, dy?: number | undefined | null): Promise<void> /** Tap a key (press + release). */ press(key: string): Promise<void> /** Tap `key` while the keys in `held` are held down. */ chord(key: string, held?: Array<string> | undefined | null): Promise<void> /** * Press `key` without releasing it. Pair with `keyUp()`. * * For a whole tap use `press()`; to hold modifiers around one tap use * `chord()`. This is the primitive for sequences neither expresses, such * as holding a key across several other actions. */ keyDown(key: string): Promise<void> /** Release a key previously pressed with `keyDown()`. */ keyUp(key: string): Promise<void> /** Type literal text into the currently focused control. */ typeText(text: string): Promise<void>}
/** * A resilient element reference that re-queries on each interaction. * * Locators never hold a live reference to a UI element. Instead, they * store a selector and resolve it on demand, making them immune to * staleness. Action methods (`press`, `typeText`, `toggle`, …) auto-wait * for the element to appear before acting, up to the process-wide default * timeout — 5 seconds unless overridden via `setDefaultTimeout()` or the * `XA11Y_DEFAULT_TIMEOUT` environment variable. * * Locators are cheap to clone — the chaining methods (`child`, `descendant`, * `nth`, `first`) return new locators rather than mutating in place. * * @example * ```ts * const app = await App.byName('MyApp');Errors
Section titled “Errors”All operations throw subclasses of XA11yError. Catch a specific subclass with instanceof and let the rest propagate.
XA11yError
Section titled “XA11yError”Base class for all xa11y errors.
PermissionDeniedError
Section titled “PermissionDeniedError”Accessibility permissions have not been granted.
AccessibilityNotEnabledError
Section titled “AccessibilityNotEnabledError”The target app advertises an accessibility tree but it is empty.
Raised on Linux when a Chromium/Electron app is launched without
--force-renderer-accessibility (or the ACCESSIBILITY_ENABLED=1
environment variable), so the renderer accessibility bridge never
populates the window’s subtree.
SelectorNotMatchedError
Section titled “SelectorNotMatchedError”No element matched the selector (also used for stale elements).
Carries a structured diagnosis so the failure is understandable without
re-running it under manual tree dumps. Every field is always present
(null / [] when not applicable); the same content is rendered into
the message.
Properties
Section titled “Properties”selector
Section titled “selector”Type: string | null
The selector that failed to match.
condition
Section titled “condition”Type: string | null
What the operation was waiting for / trying to find, if known.
lastObserved
Section titled “lastObserved”Type: string | null
What the failing operation last observed.
candidates
Section titled “candidates”Type: string[]
Bounded near-miss candidates (e.g. same-role elements).
Type: string | null
Bounded rendering of the search scope (tree dump or app list).
elapsedMs
Section titled “elapsedMs”Type: number | null
Always null for this class (parity with TimeoutError).
ActionNotSupportedError
Section titled “ActionNotSupportedError”The requested action is not supported on the target element.
TimeoutError
Section titled “TimeoutError”An operation exceeded its timeout.
Carries a structured diagnosis: what the wait was for (condition +
selector), what it last observed, and — when the selector never
matched — bounded scope context (candidates + scope). Every field is
always present (null / [] when not applicable); the same content is
rendered into the message.
Properties
Section titled “Properties”elapsedMs
Section titled “elapsedMs”Type: number | null
Wall-clock milliseconds the operation waited before giving up.
condition
Section titled “condition”Type: string | null
What the wait was for: 'visible', 'attached', 'press target actionable (visible && enabled)', …
selector
Section titled “selector”Type: string | null
The selector being resolved, when the wait had one.
lastObserved
Section titled “lastObserved”Type: string | null
The last poll’s observation (matched-with-states vs never matched).
candidates
Section titled “candidates”Type: string[]
Bounded near-miss candidates; collected only when the selector never matched.
Type: string | null
Bounded rendering of the search scope; collected only when the selector never matched.
InvalidSelectorError
Section titled “InvalidSelectorError”The selector string has invalid syntax.
InvalidActionDataError
Section titled “InvalidActionDataError”The data passed to an action method was rejected (e.g. out-of-range slider value).
PlatformError
Section titled “PlatformError”An OS-level accessibility error occurred.
Classes
Section titled “Classes”Locator
Section titled “Locator”Properties
Section titled “Properties”selector
Section titled “selector”Type: string
The CSS-like selector string for this locator.
Methods
Section titled “Methods”nth(n: number): Locator
Section titled “nth(n: number): Locator”Return a new Locator that selects the n-th match (1-based).
first(): Locator
Section titled “first(): Locator”Return a new Locator that selects the first match.
child(selector: string): Locator
Section titled “child(selector: string): Locator”Return a new Locator scoped to direct children matching selector.
descendant(selector: string): Locator
Section titled “descendant(selector: string): Locator”Return a new Locator scoped to descendants matching selector.
exists(): Promise<boolean>
Section titled “exists(): Promise<boolean>”Check whether a matching element exists (does not throw on miss).
count(): Promise<number>
Section titled “count(): Promise<number>”Count matching elements.
element(): Promise<Element>
Section titled “element(): Promise<Element>”Resolve to a single [Element] snapshot. Throws SelectorNotMatchedError
if no element matches.
elements(): Promise<Element[]>
Section titled “elements(): Promise<Element[]>”Resolve to all matching [Element] snapshots.
tree(maxDepth?: number | null): Promise<TreeNode>
Section titled “tree(maxDepth?: number | null): Promise<TreeNode>”Capture the subtree rooted at the matched element as a recursive snapshot.
maxDepth limits traversal depth: 0 = only this node (no children),
1 = node + direct children, and so on. Omit for the full subtree.
Resolves the selector once; rejects with SelectorNotMatchedError
if no match — does not auto-wait.
dump(maxDepth?: number | null): Promise<string>
Section titled “dump(maxDepth?: number | null): Promise<string>”Render the subtree rooted at the matched element as an indented string.
Returns the string without printing it. Same depth and resolution
semantics as tree().
press(): Promise<void>
Section titled “press(): Promise<void>”Click / invoke the matched element.
Auto-waits for the element to exist before acting. For elements whose
primary activation is toggle or select (checkbox, tab, radio),
press dispatches to that semantic — there is no need to distinguish.
focus(): Promise<void>
Section titled “focus(): Promise<void>”Move keyboard focus to the matched element.
blur(): Promise<void>
Section titled “blur(): Promise<void>”Remove keyboard focus from the matched element.
Not supported on Linux or Windows — on those platforms this rejects
with ActionNotSupportedError.
toggle(): Promise<void>
Section titled “toggle(): Promise<void>”Toggle a two- or three-state control (checkbox, switch, toggle button).
expand(): Promise<void>
Section titled “expand(): Promise<void>”Expand a disclosure, menu, or tree item.
collapse(): Promise<void>
Section titled “collapse(): Promise<void>”Collapse a disclosure, menu, or tree item.
select(): Promise<void>
Section titled “select(): Promise<void>”Select the matched element (list item, tab, row).
showMenu(): Promise<void>
Section titled “showMenu(): Promise<void>”Open the element’s context menu.
scrollIntoView(): Promise<void>
Section titled “scrollIntoView(): Promise<void>”Scroll the element into the visible area.
No-op on macOS — the macOS accessibility API has no equivalent. Uses
Component.ScrollTo on Linux and ScrollItemPattern on Windows.
increment(): Promise<void>
Section titled “increment(): Promise<void>”Increment a numeric value (slider, spin button) by its platform step.
decrement(): Promise<void>
Section titled “decrement(): Promise<void>”Decrement a numeric value (slider, spin button) by its platform step.
setValue(value: string): Promise<void>
Section titled “setValue(value: string): Promise<void>”Set the text value of the matched element. Replaces the entire value
rather than inserting at the caret — use typeText for insertion.
setNumericValue(value: number): Promise<void>
Section titled “setNumericValue(value: number): Promise<void>”Set the numeric value of the matched element (slider, spin button).
typeText(text: string): Promise<void>
Section titled “typeText(text: string): Promise<void>”Type text at the current caret position.
Uses the platform accessibility API — never simulates keyboard events.
For synthesised keystrokes (global shortcuts, drag gestures), use the
InputSim surface instead.
selectText(start: number, end: number): Promise<void>
Section titled “selectText(start: number, end: number): Promise<void>”Select the text range from start to end (0-based character offsets).
Rejects with InvalidActionDataError if start > end.
performAction(action: string): Promise<void>
Section titled “performAction(action: string): Promise<void>”Perform a custom action by its snake_case name.
Use this for actions the element advertises in its actions list
that don’t have a dedicated method. Rejects with
ActionNotSupportedError if the element does not advertise action.
activate(): Promise<void>
Section titled “activate(): Promise<void>”Activate the matched window: bring it to the foreground and give it focus.
minimize(): Promise<void>
Section titled “minimize(): Promise<void>”Minimize the matched window.
maximize(): Promise<void>
Section titled “maximize(): Promise<void>”Maximize the matched window.
restore(): Promise<void>
Section titled “restore(): Promise<void>”Restore the matched window to its normal state.
close(): Promise<void>
Section titled “close(): Promise<void>”Close the matched window.
moveTo(x: number, y: number): Promise<void>
Section titled “moveTo(x: number, y: number): Promise<void>”Move the matched window to the given logical screen coordinates.
Rejects with InvalidActionDataError unless both coordinates are
finite whole numbers in the 32-bit signed range.
resizeTo(width: number, height: number): Promise<void>
Section titled “resizeTo(width: number, height: number): Promise<void>”Resize the matched window to the given logical dimensions. Rejects
with InvalidActionDataError unless both dimensions are positive
whole numbers (and no larger than the 32-bit unsigned range), before
any auto-wait polling begins.
waitVisible(timeoutSeconds?: number): Promise<Element>
Section titled “waitVisible(timeoutSeconds?: number): Promise<Element>”Wait for a matching element to become visible.
Rejects with TimeoutError if still hidden after timeoutSeconds.
waitAttached(timeoutSeconds?: number): Promise<Element>
Section titled “waitAttached(timeoutSeconds?: number): Promise<Element>”Wait for a matching element to exist in the tree (may not be visible).
Rejects with TimeoutError if no match appears within timeoutSeconds.
waitDetached(timeoutSeconds?: number): Promise<void>
Section titled “waitDetached(timeoutSeconds?: number): Promise<void>”Wait for the matching element to be removed from the tree.
waitEnabled(timeoutSeconds?: number): Promise<Element>
Section titled “waitEnabled(timeoutSeconds?: number): Promise<Element>”Wait for the matching element to become enabled (interactive).
waitHidden(timeoutSeconds?: number): Promise<void>
Section titled “waitHidden(timeoutSeconds?: number): Promise<void>”Wait for the matching element to be hidden or removed.
waitDisabled(timeoutSeconds?: number): Promise<Element>
Section titled “waitDisabled(timeoutSeconds?: number): Promise<Element>”Wait for the matching element to become disabled (non-interactive).
waitFocused(timeoutSeconds?: number): Promise<Element>
Section titled “waitFocused(timeoutSeconds?: number): Promise<Element>”Wait for the matching element to receive keyboard focus.
waitUnfocused(timeoutSeconds?: number): Promise<Element>
Section titled “waitUnfocused(timeoutSeconds?: number): Promise<Element>”Wait for the matching element to lose keyboard focus.
Screenshot
Section titled “Screenshot”A captured image: raw RGBA8 pixels plus dimensions and scale.
width and height are in physical pixels. scale is the physical-to-
logical ratio (1.0 on standard displays, 2.0 on typical Retina).
pixels.length equals width * height * 4.
legend, omitted and truncated describe what annotate drew. They
are [], [] and 0 on an unannotated capture, so consumers need no
version check.
Properties
Section titled “Properties”Type: number
Image width in physical pixels.
height
Section titled “height”Type: number
Image height in physical pixels.
Type: number
Physical-to-logical pixel ratio (1.0 on standard displays, 2.0 on typical Retina, 1.5 / 1.75 / 2.0 on common Windows / Linux HiDPI).
pixels
Section titled “pixels”Type: Buffer
Raw RGBA8 pixel bytes (width * height * 4).
legend
Section titled “legend”Type: Array<LegendEntry>
One entry per drawn box, in group order and then match order. Empty
unless annotate was passed.
omitted
Section titled “omitted”Type: Array<Omission>
Elements that matched an annotate selector but could not be drawn,
each with the reason.
truncated
Section titled “truncated”Type: number
How many matched elements were not described at all because the
annotation cap was reached. 0 when the cap did not bite.
Methods
Section titled “Methods”toPng(): Buffer
Section titled “toPng(): Buffer”Encode the image as a PNG and return the bytes.
savePng(path: string): void
Section titled “savePng(path: string): void”Encode as PNG and write to path.
ShellSurface
Section titled “ShellSurface”An OS shell surface — the taskbar, a desktop panel or dock, the macOS menu bar or a process’s status items, the desktop, or a transient shell flyout.
Construct via ShellSurface.list or ShellSurface.byKind. A
ShellSurface is not an Element — it represents the surface as a
whole and provides ShellSurface.locator to search its accessibility
tree. Every surface wraps a real platform element; xa11y adds a tag, never
a node.
Enumerating surfaces and reading their trees never opens, closes, focuses, or presses anything. Where content only exists after a press (the Windows tray overflow, macOS Control Center), press the real, advertised element and then look the surface up again:
const taskbar = await ShellSurface.byKind('taskbar', { timeout: 0 });await taskbar.locator("button[name='Show Hidden Icons']").press();const flyout = await ShellSurface.byKind('flyout', { timeout: 3000 });Static methods
Section titled “Static methods”static list(): Promise<ShellSurface[]>
Section titled “static list(): Promise<ShellSurface[]>”List the OS shell surfaces currently on screen.
The listing is live: flyout surfaces appear only while they are open,
and enumerating never opens, closes, or presses anything. A platform
with no surface of a given kind simply returns none.
static byKind(kind: ShellSurfaceKindName, options?: ShellSurfaceLookupOptions | undefined | null): Promise<ShellSurface>
Section titled “static byKind(kind: ShellSurfaceKindName, options?: ShellSurfaceLookupOptions | undefined | null): Promise<ShellSurface>”Wait for exactly one surface of kind.
kind is the snake_case name — 'menu_bar', 'status_items',
'taskbar', 'panel', 'dock', 'desktop', 'flyout',
'unknown' — and is rejected with InvalidActionDataError before any
accessibility call when it names no known kind.
Polls until the surface exists or options.timeout (ms) elapses; see
App.byName for the default-timeout behaviour. Pass
{ timeout: 0 } for a single attempt with no waiting.
Rejects with SelectorNotMatchedError both when no surface of kind
is present and when several are — ambiguity is refused rather than
first-matched, and the error’s candidates name the surfaces that were
found so the caller can disambiguate with ShellSurface.list and
a pid.
Properties
Section titled “Properties”Type: ShellSurfaceKindName
What this surface is, as a snake_case string (e.g. "taskbar",
"status_items").
Type: string
Human-readable name: the owning app for per-app surfaces ("Safari"
menu bar, "Arq" status items), the platform’s own name otherwise
("Taskbar", "Dock"). Falls back to the kind’s spelling when the
platform vends no name for the root.
Type: number | null
Owning process where the platform reports one honestly, else null.
On macOS this is the true owner. On Windows it is the host (explorer.exe / ShellHost.exe) because UIA carries no per-icon owner — reported as the host, never faked. On Linux it is the panel process.
Methods
Section titled “Methods”locator(selector: string): Locator
Section titled “locator(selector: string): Locator”Create a Locator scoped to this surface’s accessibility tree.
The locator re-resolves selector on every operation, so it always
targets the current UI state — see the Locator class for the full
API.
children(): Promise<Element[]>
Section titled “children(): Promise<Element[]>”Get direct children of the surface root.
asElement(): Element
Section titled “asElement(): Element”Get an Element handle for the surface root.
Useful for invoking Element-level methods (children(), parent(),
etc.) without going through a locator. Synchronous — the surface
already holds the root’s accessibility data.
tree(maxDepth?: number | null): Promise<TreeNode>
Section titled “tree(maxDepth?: number | null): Promise<TreeNode>”Capture this surface’s accessibility tree as a recursive snapshot, rooted at the surface element.
maxDepth limits traversal depth: 0 = only the surface node, 1 =
surface + direct children, and so on. Omit for the full subtree.
dump(maxDepth?: number | null): Promise<string>
Section titled “dump(maxDepth?: number | null): Promise<string>”Render this surface’s accessibility tree as an indented string.
Returns the string without printing it. The primary inspection helper
— call console.log(await surface.dump()) to discover the role and
name of every element in the surface before writing selectors.
For the same output from the shell, use xa11y tree --shell KIND.
AppLookupOptions
Section titled “AppLookupOptions”Options for App.byName / App.byPid.
ClickOptions
Section titled “ClickOptions”Options for InputSim.click() — core’s ClickOptions.
DragOptions
Section titled “DragOptions”Options for InputSim.drag() — core’s DragOptions.
LegendEntry
Section titled “LegendEntry”One drawn annotation box: the tag in the image, and the element it came from.
A model reads a tag off the PNG; selector is what acts on the element
that tag labels — app.locator(entry.selector).press().
Properties
Section titled “Properties”Type: string
What is drawn in the box — "B7". A group letter and a 1-based index,
with no separator that downscaling could lose.
Type: number
1-based, matching the position of this element’s locator in
annotate.
Type: number
1-based, and exactly the :nth(n) argument in selector.
selector
Section titled “selector”Type: string
A selector usable as-is against the same scope the group had.
Type: string
The element’s role, snake_case as everywhere else.
bounds
Section titled “bounds”Type: Rect
The element’s bounds in logical screen coordinates.
Type: [number, number, number]
The box colour as an [r, g, b] triple, for correlating a box with
its entry by eye.
Omission
Section titled “Omission”An element that matched an annotate selector but is not in the image.
Reported rather than dropped: a legend that disagreed with the picture, with no way to find out why, is what this exists to prevent.
Properties
Section titled “Properties”selector
Section titled “selector”Type: string
The selector that would reach this element.
Type: string
The element’s role, snake_case.
reason
Section titled “reason”Type: OmissionReasonName
Why it could not be drawn: no_bounds, zero_area or
outside_capture.
A bounding rectangle in logical screen coordinates
(device-independent points) on every platform. Origin is the top-left of
the primary display; negative x / y are valid on multi-monitor setups.
This is the same space accepted by screenshotRegion and the input layer,
so bounds can be passed straight through. To map onto captured pixels,
multiply by the screenshot’s scale (physical = logical × scale).
Properties
Section titled “Properties”Type: number
Left edge, in screen coordinates.
Type: number
Top edge, in screen coordinates.
Type: number
Width in screen-coordinate units.
height
Section titled “height”Type: number
Height in screen-coordinate units.
ShellSurfaceLookupOptions
Section titled “ShellSurfaceLookupOptions”Options for ShellSurface.byKind.
TreeNode
Section titled “TreeNode”A node in a recursive snapshot of the accessibility subtree.
Returned by Element.tree() and Locator.tree(). Each node carries the
role, display name, and value of one element, plus its children recursively.
children is empty when maxDepth was reached or the element is a leaf.
Properties
Section titled “Properties”Type: string
children
Section titled “children”Type: Array<TreeNode>
Functions
Section titled “Functions”cliMain(args: Array<string>): number
Section titled “cliMain(args: Array<string>): number”CLI entry point called from the xa11y bin script.
Runs the Rust CLI implementation with the given args (excluding the
program name) and returns the process exit code: 0 success, 1
operation failed, 2 usage error. The error message is written to stderr
by the shared entry point, so the Node, Python, and Rust launchers render
failures identically.
Returns a code rather than throwing because a thrown napi Error cannot
carry one: the shim would have to re-encode the code in the message, the
way the XA11Y_* error tags already do, and every caller would have to
decode it.
This is intentionally synchronous. It backs a process whose only job is to
run one command — for xa11y mcp that means owning stdin and stdout for
the life of the process — so there is no event loop left to starve.
getDefaultTimeout(): number
Section titled “getDefaultTimeout(): number”Get the effective process-wide default timeout, in seconds.
Resolution order: the [set_default_timeout] value, else the
XA11Y_DEFAULT_TIMEOUT environment variable, else the built-in 5.0.
inputSim(): InputSim
Section titled “inputSim(): InputSim”Construct an InputSim backed by the platform’s native input path
(CGEvent on macOS, SendInput on Windows, XTest on X11).
Throws PlatformError on a Wayland-only Linux session (no XTest
available). InputSim is cheap to hold; construct one and reuse.
locator(selector: string): Locator
Section titled “locator(selector: string): Locator”Create a top-level Locator that searches from the
system accessibility root (across all applications).
setDefaultTimeout(seconds: number): void
Section titled “setDefaultTimeout(seconds: number): void”Set the process-wide default timeout, in seconds.
Becomes the default for every auto-waiting action method, wait* call,
and app lookup (App.byName / App.byPid) that doesn’t pass an explicit
timeout. An explicit per-call timeout always wins. Takes precedence over
the XA11Y_DEFAULT_TIMEOUT environment variable (seconds, read once on
first use).
Pass 0 for “single attempt, no polling” semantics. Throws for negative
or non-finite values.