@crowecawcaw/xa11y

中文文档
0.15.4发布于 2026/10/24MITTypeScriptCommonJS零依赖构建来源已验证近 30 天下载 38.9万

Cross-platform accessibility client library for Node.js

原始使用文档
文档目录9 节
  1. Quick example
  2. Installation
  3. Async by default
  4. Locators auto-wait
  5. Subscribing to events
  6. Waiting for a single event
  7. AbortSignal support
  8. Errors
  9. License

@crowecawcaw/xa11y

npm CI License: MIT Docs

Cross-platform accessibility library for Node.js. One API for macOS, Windows, and Linux — built on top of the Rust xa11y crate, exposed via napi-rs.

Use cases: UI testing, AI agent tooling, desktop automation, accessibility auditing.

Documentation · JavaScript API · Rust API · Python API

Quick example

import { App } from '@crowecawcaw/xa11y';

const safari = await App.byName('Safari');

// Find elements with CSS-like selectors via locator
for (const button of await safari.locator('button').elements()) {
  console.log(button.name);
}

// Interact with elements (re-resolves on every call)
await safari.locator('button[name="Submit"]').press();
await safari.locator('text_field[name^="Search"]').setValue('hello world');

Installation

npm install @crowecawcaw/xa11y

Requires Node.js 18 or newer. Pre-built native binaries are published for Linux (x64/arm64), macOS (x64/arm64), and Windows (x64/arm64).

macOS: Grant your terminal (or the process running Node) two permissions in System Settings → Privacy & Security: Accessibility and Screen & System Audio Recording (macOS 26+). Accessibility lets xa11y read the AX tree. The second is required to read window content. Without it, only menu bars are visible. On macOS 27 and newer, the Accessibility grant lives in the Device Control and Data Access pane.

Async by default

Every operation that touches the accessibility tree is asynchronous and runs on a worker thread, so the Node event loop is never blocked. Property getters on Element snapshots are synchronous because the data is captured up front.

const app = await App.byName('com.example.MyApp');
const submit = await app.locator('button[name="Submit"]').element();

console.log(submit.role);   // sync — already captured
console.log(submit.enabled); // sync
await submit.children();    // async — re-queries the provider

Locators auto-wait

Action methods on Locator poll the tree until the element is visible and enabled, up to a 5-second budget, before performing the action. This makes tests resilient to UI populating asynchronously.

// Waits until the dialog appears AND its OK button is enabled, then clicks it.
await app.locator('dialog[name="Save Changes?"] button[name="OK"]').press();

Subscribing to events

Subscriptions extend Node's EventEmitter, so you can use the familiar .on() / .once() / .off() API. Events are emitted both under their specific type name and the catch-all 'event' name. Call close() (or pass an AbortSignal) to tear down the subscription.

const sub = await app.subscribe();
sub.on('focusChanged', (ev) => console.log('focus moved to', ev.target?.name));
sub.on('event', (ev) => console.log(ev.type, ev.appName));
// ... later
sub.close();

Waiting for a single event

Use waitForEvent() for Playwright-style one-shot waits with optional predicate and timeout:

const [opened] = await Promise.all([
  app.waitForEvent('windowOpened'),
  app.locator('button[name="Settings"]').press(),
]);

// With predicate + timeout
const ev = await sub.waitForEvent('focusChanged', {
  predicate: (e) => e.target?.role === 'button',
  timeout: 3000,
});

AbortSignal support

Both subscribe() and waitForEvent() accept an AbortSignal for cancellation:

const ctrl = new AbortController();
const sub = await app.subscribe({ signal: ctrl.signal });
sub.on('focusChanged', (ev) => { /* ... */ });
// ctrl.abort() closes the subscription automatically

Errors

All operations throw subclasses of XA11yError:

ClassWhen
PermissionDeniedErrorAccessibility permissions not granted (macOS)
SelectorNotMatchedErrorelement() / actions found nothing
ActionNotSupportedErrorThe element doesn't support the action
TimeoutErrorA wait* or auto-wait budget expired
InvalidSelectorErrorBad selector or action data
PlatformErrorOther OS-level failure

Catch a specific subclass and let the rest propagate:

import { App, SelectorNotMatchedError } from '@crowecawcaw/xa11y';

try {
  await app.locator('button[name="Submit"]').press();
} catch (err) {
  if (err instanceof SelectorNotMatchedError) {
    /* expected miss */
  } else {
    throw err;
  }
}

License

MIT — see LICENSE.

版本与发布记录

@crowecawcaw/xa11y 共发布 20 个版本,首次发布于 2026/04/18;过去 12 个月发布了 20 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.15.4latest2026/10/2417 天前
0.15.32026/10/2120 天前
0.15.22026/09/301 个月前
0.15.12026/09/291 个月前
0.15.02026/09/191 个月前
0.14.02026/09/092 个月前

其他发布通道:placeholder → 0.0.1-placeholder.0。

关于 @crowecawcaw/xa11y 的常见问题

@crowecawcaw/xa11y 是什么?

Cross-platform accessibility client library for Node.js

如何安装 @crowecawcaw/xa11y?

在项目目录运行 npm install @crowecawcaw/xa11y,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 xa11y,可以用 npx xa11y 直接运行。

@crowecawcaw/xa11y 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@crowecawcaw/xa11y 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@crowecawcaw/xa11y 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@crowecawcaw/xa11y 可以商用吗?

@crowecawcaw/xa11y 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@crowecawcaw/xa11y 的下载量有多少?

根据 npm 官方下载统计,@crowecawcaw/xa11y 在 2026/10/11 – 2026/11/09 这 30 天内被下载 388,933 次,日均约 12,964 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@crowecawcaw/xa11y 还在维护吗?

最新版本 0.15.4 发布于 2026/10/24(17 天前);至今共发布 20 个版本,其中过去 12 个月发布了 20 个;首次发布于 2026/04/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。