@real-a11y-dev/core
TL;DR — Extracts a browser-accurate accessibility tree from any DOM element, as plain data (
Map<string, SemanticNode>). Zero runtime dependencies. Reach for this when you're building your own tooling on top of the engine; for apps, use one of the wrapper packages.
The extraction engine. Every other package is built on top of this.
Install
# Most apps — dev-only (used in tests or behind a dev gate)
npm install -D @real-a11y-dev/core
# Library authors / tools that ship core at runtime — regular dep or peer
npm install @real-a11y-dev/core@real-a11y-dev/core has no runtime dependencies. It uses standard DOM APIs only.
Which type of dependency do I need?
-D(dev) is the right default for most apps — you're usingcoreinside tests, Storybook, or a dev-only audit panel gated byimport.meta.env.DEV/process.env.NODE_ENV. See Keep it out of production.- Regular
dependencyif you're publishing your own package that usescoreat runtime (e.g. a new audit tool on top of the engine). peerDependencyif you're publishing a library that composescorewith other Real A11y packages — lets consumers share a single copy.
Extraction
extractA11yTree(root)
Extracts the accessibility tree from a DOM element.
import { extractA11yTree } from "@real-a11y-dev/core";
const tree = extractA11yTree(document.getElementById("app"));
// tree: { nodes: Map<string, SemanticNode>; rootId: string }Resolves ARIA roles, computes accessible names via the full ANDC algorithm, detects hidden subtrees, and maps interaction capabilities.
extractDomTree(root)
Same shape as extractA11yTree, but uses raw tag names as roles instead of ARIA roles. Useful when you want to audit DOM structure rather than accessibility semantics.
import { extractDomTree } from "@real-a11y-dev/core";
const tree = extractDomTree(document.querySelector("main"));Query helpers
findByRole(tree, role, options?)
Returns the first SemanticNode matching the given role, or null.
import { extractA11yTree, findByRole } from "@real-a11y-dev/core";
const tree = extractA11yTree(root);
const submitBtn = findByRole(tree, "button", { name: /submit/i });Options:
| Option | Type | Description |
|---|---|---|
name | string | RegExp | Filter by accessible name. String: exact match (case/whitespace-normalized). RegExp: .test(). |
level | number | Filter by heading level (1–6). |
checked | boolean | Filter by aria-checked state. |
expanded | boolean | Filter by aria-expanded state. |
selected | boolean | Filter by aria-selected state. |
pressed | boolean | Filter by aria-pressed state. |
disabled | boolean | Filter by aria-disabled state. |
includeHidden | boolean | Include nodes in aria-hidden subtrees (default: false). |
findAllByRole(tree, role, options?)
Returns all matching nodes as SemanticNode[].
const headings = findAllByRole(tree, "heading", { level: 2 });Tree traversal
linearize(tree, options?)
Returns all nodes in pre-order (DOM order), skipping hidden nodes by default.
import { linearize } from "@real-a11y-dev/core";
const nodes = linearize(tree);
// SemanticNode[] in DOM orderOptions:
| Option | Type | Default | Description |
|---|---|---|---|
includeHidden | boolean | false | Include aria-hidden subtrees |
Structure queries
getOutline(tree)
Returns heading nodes as a flat outline list.
import { getOutline } from "@real-a11y-dev/core";
const outline = getOutline(tree);
// [{ id, level, name }, ...]getTabSequence(tree)
Returns focusable nodes in computed tab order.
import { getTabSequence } from "@real-a11y-dev/core";
const sequence = getTabSequence(tree);
// SemanticNode[] — positive tabindex ascending, then natural orderTree diffing
diffTrees(before, after)
Compares two tree snapshots and returns what changed.
import { diffTrees } from "@real-a11y-dev/core";
const before = extractA11yTree(root);
// ...user interaction...
const after = extractA11yTree(root);
const diff = diffTrees(before, after);
// { added: SemanticNode[], removed: SemanticNode[], changed: NodeChange[] }NodeChange:
interface NodeChange {
id: string;
before: Partial<SemanticNode>;
after: Partial<SemanticNode>;
fields: string[]; // e.g. ["a11y.name", "a11y.states.expanded"]
}DOM observation
DomObserver
Watches a DOM subtree for mutations and calls a callback (debounced).
import { DomObserver } from "@real-a11y-dev/core";
const observer = new DomObserver(root, () => {
console.log("DOM changed, re-extract");
}, 200); // 200ms debounce
observer.start();
// Later:
observer.stop();Types
import type {
SemanticNode,
SemanticTree,
SemanticNavigatorConfig,
FindByRoleOptions,
OutlineEntry,
NodeChange,
TreeDiff,
LinearizeOptions,
QueryInput,
TreeMode,
ActionType,
} from "@real-a11y-dev/core";