Out of Order

GitHub
API reference

Every package, in full

The full API of every npm package, one block each. Every function is kept together with the types it takes and hands back.

@out-of-order/core

npm i -D @out-of-order/core

The analyzer. It computes the tab sequence, grades it against the rules, and reshapes the findings. Pure and framework-free: every other package builds on it.

audit()function

audit(root?, options?) → AuditResult

Computes the tab sequence for root and grades it against the enabled rules. It runs in the browser only, because tabbable uses real CSS layout for visibility and several rules read bounding rects.

The result's violations hold live Elements. For a printable or serializable view, pass the result to formatViolations().

Parameters

Parameter Type Description
root Document | Element Optional, defaults to document. The subtree to analyze. A Document analyzes the whole page, exactly like tabbing through it.
options AuditOptions Optional. Per-rule severity overrides and custom rules. See Options & severity.

Returns → AuditResulttype

Holds the computed tab sequence, every violation found, and the overall verdict.

Property Type Description
valid boolean True when no enabled rule produced an error. Warnings are advisory and never flip it, so read violations when you want to surface those too.
sequence SequenceEntry[] Every tab stop, in the exact order the Tab key reaches it.
violations Violation[] One entry per offending element, each carrying the rules it failed, across all enabled rules and both severities.

SequenceEntrytype

One entry per tab stop in AuditResult.sequence.

Property Type Description
element Element The focusable node at this stop.
selector string A short, CSS-ish path to the element, for messages and logs.
orderIndex number Its zero-based position in the tab sequence.
tabIndex number The resolved tabindex, 0 when the element is focusable without one.
rect DOMRect The element's bounding rect at analysis time, from real browser layout. This is why several rules need a real browser.

Violationtype

One entry per offending element in AuditResult.violations, carrying every rule it failed.

Property Type Description
element Element The offending element.
selector string A CSS-ish path to that element, for messages and logs.
orderIndex? number Its position in the tab sequence, present only when it is a stop.
issues Issue[] The rules this element failed, error-severity first.

Issuetype

A single rule failure on one element.

Property Type Description
rule string The id of the rule that fired, a built-in id or a custom rule's own. Stable, so you can key or filter on it.
severity "error" | "warning" How serious the finding is, after any per-call override.
message string A plain-language account of what is wrong.
fix? string A suggested remediation, when the rule has one.
docs? string A spec link (WCAG, WAI-ARIA, or ARIA APG) for the rule.
relatedElements? Element[] Other elements that share this issue's root cause. Ringed alongside the violation's element but not reported as separate violations, so one missing fix does not become N findings.
ignored? boolean True when the element approves this rule via data-ooo-ignore. An ignored error never flips valid.

Options & severity

The severity values and the options object taken by audit() and, through TraceOptions.audit, by trace().

Severity & RuleOverridetypes

The grades a rule reports at, and what an override can set it to.

Type Definition Description
Severity "error" | "warning" The two grades a rule can report at.
RuleOverride Severity | "off" What you set a rule to in an override. The value "off" disables the rule.

AuditOptionstype

The options object passed to audit().

Property Type Description
rules? Partial<Record<RuleId, RuleOverride>> Per-rule overrides. Omit a rule to keep its default. Set "error" or "warning" to enable it at that grade, or "off" to disable it.
customRules? Rule[] Extra rules that run alongside the built-ins, overridable through rules like any built-in. See custom rules.

RuleId is the union of the built-in rule ids, so overrides autocomplete. The full list is on the rules page, and the ids with their default grades are also exported as data, see Helpers & exports.

formatViolations()function

formatViolations(result, format) → string | ByElement[] | ByViolation[] | FlatIssue[]

Reshapes a result's violations into the named view and leaves the result itself untouched. "text" renders a human-readable block. The other views are serializable arrays with every element reference flattened to its selector string, so they survive JSON.stringify. The overloads narrow the return type when format is a literal.

AuditFormattype

The four views, and what each returns.

Format Returns Description
"text" string A ready-to-print block: one paragraph per element, its issues indented.
"by-element" ByElement[] One entry per offending element with its issues nested, plus an issueCount. The serializable twin of Violation.
"by-violation" ByViolation[] One entry per failed rule with the offending elements nested, plus an elementCount. Errors sort before warnings.
"flat" FlatIssue[] One entry per element-issue pair, nothing nested: a SerializedIssue plus the element's selector and orderIndex?.

SerializedIssuetype

The issue shape shared by the formatted views: an Issue with its element references flattened to selector strings.

Property Type Description
rule string The id of the rule that fired.
severity Severity How serious the finding is.
message string What is wrong.
fix? string A suggested remediation, when the rule has one.
docs? string The rule's spec link.
related? string[] Selectors of the elements sharing this issue's root cause.
ignored? boolean Approved via data-ooo-ignore.

ByElementtype

One "by-element" entry: an offending element with its failures nested.

Property Type Description
selector string A CSS-ish path to the offending element.
orderIndex? number Its position in the tab sequence, present only when it is a stop.
issueCount number How many rules the element failed (issues.length).
issues SerializedIssue[] The failures themselves, error-severity first.

ByViolationtype

One "by-violation" entry: a failed rule with every element that tripped it nested.

Property Type Description
rule string The id of the failed rule.
severity Severity The rule's grade, after any per-call override.
docs? string The rule's spec link.
elementCount number How many elements failed it (elements.length).
elements { selector, orderIndex?, message, fix?, related?, ignored? }[] The offending elements, each with its own message and, when present, the related selectors and its data-ooo-ignore approval.

FlatIssuetype

One "flat" entry. Extends SerializedIssue with where the issue sits, so a single row carries everything.

Property Type Description
selector string A CSS-ish path to the offending element.
orderIndex? number Its position in the tab sequence, present only when it is a stop.
SerializedIssue Plus every SerializedIssue field, flattened in.

Custom rules

A rule is a pure function over the computed sequence. Pass your own through AuditOptions.customRules and they flow into the result and the overlay like any other.

Ruletype

One custom rule.

Property Type Description
id string Surfaced as rule on every Issue the rule produces.
docs? string The spec link the rule is grounded in.
severity Severity The grade its findings get unless the caller overrides it through AuditOptions.rules.
run (sequence: SequenceEntry[], ctx: RuleContext) => Finding[] The rule itself, run over the sequence.

RuleContexttype

Handed to a rule's run as its second argument.

Property Type Description
container Element The analyzed root, so a rule can look beyond the tab sequence.
inSequence Set<Element> A fast "is this element a tab stop?" test.

Findingtype

Returned by a rule's run, one per issue.

Property Type Description
message string What is wrong.
fix? string A suggested remediation. Shown separately from the message (the overlay renders it as a "Possible fix" line).
target SequenceEntry | Element The element the finding is about, a SequenceEntry when it is a tab stop.
relatedElements? Element[] Other elements sharing the same root cause.

For a worked example, see adding your own rule.

Helpers & exports

The DOM helpers the built-in rules lean on, exported so a custom rule can reuse them.

Export Signature Description
isInteractive (el: Element) => boolean Returns whether an element is interactive, meaning a native control or an element with an interactive ARIA role.
selectorFor (el: Element) => string Returns a short, CSS-ish path to an element, useful for messages and logs.
isScreenReaderOnly (el: Element, rect?: DOMRect) => boolean Returns whether an element is an intentional .sr-only-style utility (tiny and clipped), the standard way to expose text to screen readers, which a rule must not flag as invisible.
isRuleIgnored (el: Element, ruleId: string) => boolean Returns whether the element approves the rule via data-ooo-ignore. Element-scoped, never inherited by descendants.
composedDescendants (root: ParentNode) => Generator<Element> Yields every element under root in tree order, descending into open shadow roots. The composed-tree stand-in for querySelectorAll("*"), which never enters a shadow root.

The rule set as data

The built-in rule set, exported for building tooling around it: option pickers, docs, config validation.

Export Type Description
RuleIdtype "no-positive-tabindex" | … The union of the built-in rule ids, what AuditOptions.rules keys on. The full list, each with its clause, is on the rules page.
DEFAULT_SEVERITYconst Record<RuleId, Severity> Every built-in rule's default grade, keyed by id. What the overrides are applied against.

@out-of-order/vitest

npm i -D @out-of-order/vitest

The audit as a one-line assertion for Vitest Browser Mode. Released, but the API is still settling.

toHaveValidTabOrder()matcher

expect(root).toHaveValidTabOrder(options?)

Import the package once in a setup file and it registers the matcher and its types: import "@out-of-order/vitest";.

The assertion target must be an Element or a Document. It runs audit(root, options) and passes on AuditResult.valid, so warnings never fail a test but errors do. A failure prints the "text" view of the violations. Works with .not, which expects at least one error.

It refuses to run outside a real browser. With no DOM at all, or under a layout-less simulated DOM like jsdom or happy-dom, it throws and tells you to enable Vitest Browser Mode instead of silently passing on meaningless layout.

Parameters

Parameter Type Description
options AuditOptions Optional. The same per-rule overrides and custom rules audit() takes. See Options & severity.

Setup and configuration live in the vitest README.

@out-of-order/trace

npm i -D @out-of-order/trace

The visual overlay, built on the analyzer: numbered tab stops, the path between them, and every finding ringed in place on the live page.

trace()function

trace(options?) → TraceHandle

Mounts the overlay layer, draws the first analysis, and starts observing. It re-analyzes itself on DOM mutation, so most pages need nothing past the call.

The audit-shaped fields here (AuditOptions, AuditResult) are core's types. The overlay depends on core but does not re-export it, so for the headless audit() path install @out-of-order/core and import from there.

Parameters → TraceOptionstype

Every field is optional.

Property Type Description
root? Document | Element The subtree to analyze. Defaults to document.
audit? AuditOptions Rule overrides and custom rules, forwarded to audit() on every analysis.
motion? MotionMode Animation behaviour. Defaults to "auto", which follows the user's prefers-reduced-motion setting, live.
peekKey? ModifierKey Tap it to peek through the overlay at the page beneath without hiding it, tap again to restore. Defaults to "Alt".
onResult? (result: AuditResult) => void Called after every re-analysis with the fresh result. The first call is synchronous, before trace() returns.

Returns → TraceHandletype

For driving the overlay after the mount.

Member Type Description
visible boolean Read-only. Reports whether the overlay is currently visible.
setVisible (visible: boolean) => void Shows or hides the whole overlay, including its badges, lines, and rings.
toggle () => void Flips the overlay between shown and hidden.
destroy () => void Removes the overlay layer, observers, and listeners.
result AuditResult | null The latest analysis result, or null before the first draw.

MotionMode & ModifierKeytypes

The two option unions above, exported by name.

Type Definition Description
MotionMode "auto" | "on" | "off" Whether the overlay animates. "auto" follows prefers-reduced-motion, the other two force it.
ModifierKey "Alt" | "Control" | "Shift" | "Meta" The modifier that drives the peek toggle.

@out-of-order/cli

npx @out-of-order/cli <url>

The audit from the terminal, against any URL. No JS API: it launches headless Chromium, runs the same audit(), and prints the findings.

out-of-ordercommand

out-of-order <url> [options]

Point it at a URL, a bare domain (https:// is assumed, http:// for localhost), or a local HTML file. Pages that are still an empty shell at load, common for SPAs, are re-audited up to --tries times until something tabbable renders.

Option Value Description
--format text | by-element | by-violation | flat | json Output shape, default text. The middle three are the formatViolations() views. json is CLI-only: the full result with valid, the tab sequence, and the violations.
--rule <id>=<level> Set a rule to off, error, or warning. Repeatable.
--wait <selector> Wait for a selector before auditing, for pages that render after load.
--tries <n> Re-audit up to n times, a second apart, while the page has no tabbable elements. Default 5.
--timeout <ms> Navigation and selector timeout, default 30000.
--viewport <WxH> Viewport size, for example 1440x900.
--auth <file> Storage-state file to load, saved by login. Default: the per-host file under ~/.config/out-of-order/auth.
--overlay boolean Open a headed browser with the visual overlay drawn on the live page instead of printing. Excludes --format.
--version boolean Print the version.
--help boolean Show the usage message.

Exit codes

Code Meaning Description
0 valid No error-severity violations. Warnings may still have printed.
1 violations At least one error-severity violation, so a CI step fails on it.
2 failed run The run itself failed: a usage error, a crash, a non-OK HTTP status, or a page with no tabbable elements on any try.

The full option list is also in the CLI README.

out-of-order logincommand

out-of-order login <url> [options]

For pages behind a login. Every later audit of that host picks it up automatically.

Needs an http(s) <url>, and takes only the three options below. The session is stored per host under ~/.config/out-of-order/auth unless --auth names a file.

Option Value Description
--auth <file> Where to save the storage state. Pass the same file to later audits with their own --auth.
--timeout <ms> Navigation timeout, default 30000.
--viewport <WxH> Viewport size, for example 1440x900.