Product design skills

references/act.md

A supporting file of the ultra11y skill.

ACT conformance — how this engine scores against a corpus it did not write

The recall matrix in this repository proves that each rule fires on the defect written FOR it. That is circular. The W3C ACT-Rules Community Group publishes rules with passed / failed / inapplicable examples authored independently of this project, so running the engine over them measures something a self-authored fixture cannot.

How to read this. An ACT example asserts something about ITS OWN rule and nothing else, so each case is judged only with the engine rules mapped to that ACT rule — never with the whole engine. Only normative findings count (an advisory recommendation never flips a criterion, so it cannot fail a case either). Rules needing a rendered page or a human call are declared, not scored — saying so beats quietly scoring zero.

Summary

Corpus1134 examples across 91 ACT rules
Sourcehttps://act-rules.github.io/testcases.json
Rules scored40
Failed examples caught125 / 176
Clean examples left alone364 / 364 — no unexplained false positive
Consistent9
Divergent (documented, 9 cases)3
Partially consistent28
Inconsistent0
Declared gaps (static, not implemented)5

Partially consistent is the ACT Rules Format's own term for a tool that never reports a false positive but does not catch everything — it is a coverage statement, not an error. Divergent means every deviation on that rule is listed below with the argument for it.

Scored rules

ACT ruleWCAGEngine rulesVerdictCaught
Image has non-empty accessible name1.1.1img-alt-missing🟨 partially consistent4/5
Letter spacing in style attributes is not !important1.4.12letter-spacing-important🟨 partially consistent3/4
HTML page has non-empty title2.4.2title-missing-empty🟨 partially consistent4/5
Visible label is part of accessible name2.5.3label-in-name-mismatch🟦 divergent (documented)3/3
Element with presentational children has no focusable content4.1.2presentational-children-focusable🟨 partially consistent2/3
Id attribute value is unique4.1.1duplicate-id✅ consistent3/3
Element marked as decorative is not exposeddecorative-marked-exposed✅ consistent3/3
Audio or video element that plays automatically has a control mechanismautoplay-media🟦 divergent (documented)5/5
Element with role attribute has required states and properties4.1.2aria-required-attr🟨 partially consistent1/2
Image button has non-empty accessible name1.1.1, 4.1.2input-image-alt-missing🟨 partially consistent2/3
HTML page lang and xml:lang attributes have matching values3.1.1html-lang-xml-lang-mismatch✅ consistent2/2
ARIA state or property is permittedaria-prohibited-attr🟨 partially consistent0/2
ARIA attribute is defined in WAI-ARIAinvalid-aria-attr✅ consistent2/2
Role attribute has valid value1.3.1invalid-aria-role✅ consistent2/2
ARIA state or property has valid valueinvalid-aria-value, live-region-conflict🟨 partially consistent9/10
Element with aria-hidden has no content in sequential focus navigation4.1.2aria-hidden-focusable🟨 partially consistent5/6
Autocomplete attribute has valid value1.3.5autocomplete-token-invalid✅ consistent5/5
Line height in style attributes is not !important1.4.12line-height-important🟨 partially consistent4/6
SVG element with explicit role has non-empty accessible name1.1.1img-alt-missing🟨 partially consistent2/4
Audio or video element avoids automatically playing audio1.4.2autoplay-media🟦 divergent (documented)2/2
Object element rendering non-text content has non-empty accessible name1.1.1object-embed-no-name🟨 partially consistent2/4
Button has non-empty accessible name4.1.2button-empty-name, icon-only-control-unnamed🟨 partially consistent4/5
Word spacing in style attributes is not !important1.4.12word-spacing-important🟨 partially consistent3/4
Headers attribute specified on a cell refers to cells in the same table element1.3.1headers-attr-dangling✅ consistent4/4
Meta viewport allows for zoom1.4.4meta-viewport-zoom-block🟨 partially consistent3/4
HTML page has lang attribute3.1.1html-lang-missing🟨 partially consistent3/4
ARIA required owned elements1.3.1aria-required-children🟨 partially consistent3/7
Meta element has no refresh delay2.2.1, 2.2.4, 3.2.5meta-refresh-redirect🟨 partially consistent3/4
HTML page lang attribute has valid language tag3.1.1lang-invalid🟨 partially consistent1/4
Meta element has no refresh delay (no exception)2.2.4, 3.2.5meta-refresh-redirect🟨 partially consistent2/4
Link has non-empty accessible name2.4.4, 2.4.9, 4.1.2link-empty-name, icon-only-control-unnamed🟨 partially consistent7/11
Iframe element has non-empty accessible name4.1.2iframe-title-missing🟨 partially consistent3/4
Table header cell has assigned cells1.3.1th-no-data-cells🟨 partially consistent0/3
Element with lang attribute has valid language tag3.1.2lang-invalid, inline-lang-change-missing🟨 partially consistent6/9
Form field has non-empty accessible name4.1.2control-label-missing🟨 partially consistent4/7
Attribute is not duplicated4.1.1duplicate-attribute✅ consistent3/3
Video element auditory content has captionsmedia-no-track🟨 partially consistent0/4
ARIA required context role1.3.1aria-required-parent🟨 partially consistent2/4
Heading has non-empty accessible name1.3.1empty-heading🟨 partially consistent7/8
Menuitem has non-empty accessible name4.1.2menuitem-empty-name✅ consistent2/2

Notes and documented divergences

  • Letter spacing in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
  • Visible label is part of accessible name · reports on Passed Example 6: an icon FONT renders the text 'search' as a glyph, so the visible label is not the text in the DOM — a fact only the rendered page carries
  • Audio or video element that plays automatically has a control mechanism · reports on Inapplicable Example 2: the source cannot tell that the referenced media has no audio track
  • Audio or video element that plays automatically has a control mechanism · reports on Passed Example 3: the pause mechanism is a custom button wired in JavaScript, not a native controls attribute
  • ARIA state or property is permitted — covers the name-prohibited roles; the full per-role permitted-attribute matrix is not encoded
  • Element with aria-hidden has no content in sequential focus navigation · reports on Passed Example 4: a focus-sentinel link inside an aria-hidden wrapper: it IS reachable by Tab, and only a runtime focus handler bounces it back — the same call axe-core makes
  • Line height in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
  • SVG element with explicit role has non-empty accessible name — role=img on <svg> is handled by the same rule
  • Audio or video element avoids automatically playing audio · reports on Inapplicable Example 2: the source cannot tell that the referenced media file is silent
  • Audio or video element avoids automatically playing audio · reports on Passed Example 3: the pause mechanism is a custom button wired in JavaScript, not a native controls attribute
  • Audio or video element avoids automatically playing audio · reports on Passed Example 2: a #t= media fragment shortening playback below 3s is not resolvable from source
  • Word spacing in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
  • Meta element has no refresh delay (no exception) — this variant drops the >20h exception the engine honours, so long delays are knowingly not reported
  • Iframe element has non-empty accessible name · reports on Inapplicable Example 3: a tabindex=-1 iframe is still exposed to assistive tech and still needs a title (RGAA 2.1 requires one unconditionally)
  • Table header cell has assigned cells — only the explicit headers-wired shape is decided; scope-based assignment needs a full table model
  • Element with lang attribute has valid language tag · reports on Inapplicable Example 2: lang="" on an element carrying text declares no language for that text; ACT deems the rule inapplicable, this engine reports it under 3.1.2
  • Form field has non-empty accessible nameplaceholder-as-label is deliberately NOT mapped: a placeholder does contribute to the accessible name, so ACT passes it — ultra11y still reports it, as a stricter house rule under 3.3.2.
  • Video element auditory content has captions — presence of a caption track; whether the captions are accurate is a judgment call

Declared gaps — statically decidable, not implemented yet

ACT ruleWCAGWhy it is not covered
Document has heading for non-repeated contenta heading for the non-repeated content (h1-missing is advisory, so it does not count)
Document has a landmark with non-repeated contentACT asks that the non-repeated content sit in SOME landmark — a weaker claim than missing-main-landmark, which requires a <main>, so the two are not equivalent
Bypass Blocks of Repeated Content2.4.1presence of a bypass mechanism (landmark or skip link)
No keyboard shortcut uses only printable characters2.1.42.1.4 single-character keyboard shortcuts
Document has an instrument to move focus to non-repeated contentpresence of a bypass instrument

Out of the static engine's reach — routed, not ignored

ACT ruleWCAGDecided by
Text has enhanced contrast1.4.6rendered (scan) — AAA enhanced contrast — outside the AA core
Scrollable element is keyboard accessible2.1.1, 2.1.3rendered (scan)
HTML graphics contain no text1.4.5, 1.4.9rendered (scan) — text baked into a graphic
Audio and visuals of video element have transcript1.2.8judgment (agent)
Video element visual content has audio descriptionjudgment (agent)
Video element visual content has strict accessible alternative1.2.5judgment (agent)
Audio element content has transcriptjudgment (agent)
Error message describes invalid form field value3.3.1judgment (agent)
Block of repeated content is collapsiblerendered (scan)
Iframe elements with identical accessible names have equivalent purpose4.1.2judgment (agent)
Zoomed text node is not clipped with CSS overflow1.4.4rendered (scan) — clipping under zoom — probed by scan --runtime local
Link in context is descriptive2.4.4, 2.4.9judgment (agent) — link purpose in context (2.4.4)
Device motion based changes to the content can also be created from the user interface2.5.4judgment (agent)
Focusable element has no keyboard trap2.1.2rendered (scan)
Content has alternative for visual reference1.3.3judgment (agent) — sensory characteristics (1.3.3)
DEPRECATED — Image filename is accessible name for image1.1.1withdrawn upstream
Focusable element has no keyboard trap via standard navigationrendered (scan)
Audio or video element that plays automatically has no audio that lasts more than 3 secondsrendered (scan) — needs the media's duration
Video element content is media alternative for textjudgment (agent)
DEPRECATED — Video element visual-only content has description trackwithdrawn upstream
Audio element content is media alternative for textjudgment (agent)
Text has minimum contrast1.4.3, 1.4.6rendered (scan) — computed contrast; only inline literal colour pairs are decided statically (contrast-literal)
Link is descriptive2.4.9judgment (agent)
Iframe with negative tabindex has no interactive elements2.1.1rendered (scan) — needs the iframe's own document
Links with identical accessible names have equivalent purpose2.4.9judgment (agent)
Orientation of the page is not restricted using CSS transform property1.3.4rendered (scan) — orientation lock via CSS transform
Heading is descriptive2.4.6judgment (agent) — is the heading descriptive (2.4.6)
Device motion based changes to the content can be disabled2.5.4judgment (agent)
Video element visual-only content has accessible alternative1.2.1judgment (agent)
HTML page title is descriptive2.4.2judgment (agent)
Video element visual content has accessible alternative1.2.3, 1.2.5, 1.2.8judgment (agent)
Form field label is descriptive2.4.6judgment (agent)
Video element visual-only content has audio track alternativejudgment (agent)
Audio element content has text alternative1.2.1judgment (agent)
Image not in the accessibility tree is decorative1.1.1judgment (agent) — is the image genuinely decorative
Video element auditory content has accessible alternative1.2.2judgment (agent)
Focusable element has no keyboard trap via non-standard navigationrendered (scan)
Video element visual-only content has transcriptjudgment (agent)
Text content that changes automatically can be paused, stopped or hidden2.2.2rendered (scan)
DEPRECATED — Video element visual content has description trackwithdrawn upstream
Video element visual-only content is media alternative for textjudgment (agent)
Links with identical accessible names and same context serve equivalent purpose2.4.4, 2.4.9judgment (agent)
HTML element language subtag matches language3.1.2judgment (agent) — does the subtag match the actual text language
Element in sequential focus order has visible focus2.4.7rendered (scan) — visible focus (2.4.7) — probed by scan --runtime local
Image accessible name is descriptive1.1.1judgment (agent) — is the alt relevant (1.1.1)
HTML page language subtag matches default language3.1.1judgment (agent)

The corpus is vendored at scripts/vendor/act-testcases.json (refreshed by pnpm run build:act:refresh, and daily by the act-refresh workflow) so the suite stays offline and deterministic. ACT-Rules Community Group test cases are © their contributors under the W3C Software and Document License — see NOTICE.

On this page