Skip to main content
TECHNICAL REFERENCE

Custom Rules & Heuristics

A11yEngine pairs standard axe-core 4.10.0 compliance checks with 43 proprietary local heuristic rules to audit interactive controls, media accessibility, focus safety, WAVE parity, and secure PII compliance.

Rule 1 - custom-focus-trap-and-return

Modal Dialog Focus Trap & Return

CriticalSC 2.4.3 (Focus Order) - Level A

Simulates modal dismissal via Escape key and verifies if keyboard focus is properly trapped inside active dialogs and returned to trigger elements upon close.

❌ Non-Compliant Implementation
<div role="dialog"><button onclick="closeModal()">Close</button></div>
✓ Remediation Code (Tailwind/HTML)
<div role="dialog" aria-modal="true" aria-labelledby="modal-title"><h2 id="modal-title">Terms</h2><button onclick="closeModal()" ref={closeBtnRef}>Close</button></div>
Rule 2 - custom-widget-contract

ARIA Accordion / Widget State Contract

HighSC 4.1.2 (Name, Role, Value) - Level A

Validates aria-expanded toggle state transitions and verifies that aria-controls points to existing DOM target elements.

❌ Non-Compliant Implementation
<button onclick="toggle()">Accordion</button>
✓ Remediation Code (Tailwind/HTML)
<button aria-expanded="true" aria-controls="panel-1" onclick="toggle()">Accordion</button>
<div id="panel-1">Content</div>
Rule 3 - custom-live-region-chatter

Excessive Live Region Announcement Chatter

HighSC 4.1.3 (Status Messages) - Level AA

Monitors dynamic DOM mutations to prevent excessive or rapid aria-live updates from overwhelming screen readers.

❌ Non-Compliant Implementation
<div aria-live="assertive">Position updating every 50ms...</div>
✓ Remediation Code (Tailwind/HTML)
<div aria-live="polite" aria-atomic="true">Status: Processing complete.</div>
Rule 4 - custom-spa-route-focus

SPA Navigation Focus Reset Loss

HighSC 2.4.3 (Focus Order) - Level A

Detects client-side SPA route transitions in React, Next.js, and Vue, verifying keyboard focus resets to the main heading or container.

❌ Non-Compliant Implementation
router.push('/dashboard'); // Focus remains stuck on previous page link
✓ Remediation Code (Tailwind/HTML)
router.push('/dashboard'); document.querySelector('h1')?.focus();
Rule 5 - custom-focus-outline-reset

Invisible Keyboard Focus Indicator

HighSC 2.4.7 (Focus Visible) - Level AA

Flags elements that override the browser default focus indicator (using outline:none, outline:0, or focus:outline-none) without declaring a visible fallback ring.

❌ Non-Compliant Implementation
<button class="bg-[#111111] text-white focus:outline-none">Complete Purchase</button>
✓ Remediation Code (Tailwind/HTML)
<button class="bg-[#111111] text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">Complete Purchase</button>
Rule 6 - custom-tabindex-improper

Hardcoded Positive Tabindex

MediumSC 2.1.1 (Keyboard) - Level A

Detects element declarations with positive tabindex attributes (tabindex > 0). Hardcoding positive tabindex values disrupts natural top-down tabbing flow.

❌ Non-Compliant Implementation
<a href="/pricing" tabindex="3">Pricing</a>
✓ Remediation Code (Tailwind/HTML)
<a href="/pricing">Pricing</a>
Rule 7 - custom-keyboard-nav-missing

Unreachable Clickable Custom Control

HighSC 2.1.1 (Keyboard) - Level A

Catches non-interactive elements (like <div> or <span>) that have click listeners but lack tabindex attributes or keyboard event handlers.

❌ Non-Compliant Implementation
<div onclick="submitOrder()" role="button">Buy Now</div>
✓ Remediation Code (Tailwind/HTML)
<div onclick="submitOrder()" role="button" tabindex="0" onkeydown="if(event.key==='Enter'||event.key===' '){submitOrder();}">Buy Now</div>
Rule 8 - custom-aria-icon-missing

Icon-Only Control Lacks Description

CriticalSC 1.3.1 & SC 4.1.2 - Level A

Flags links and buttons containing only SVG or vector glyphs with no textual label or aria-label attributes.

❌ Non-Compliant Implementation
<button><svg class="w-4 h-4"></svg></button>
✓ Remediation Code (Tailwind/HTML)
<button aria-label="Delete item permanently"><svg class="w-4 h-4"></svg></button>
Rule 9 - custom-accessible-name-mismatch

Visible Label Mismatch in ARIA Name

MediumSC 2.5.3 (Label in Name) - Level A

Identifies custom controls where the visible text string is not included inside the aria-label attribute for speech recognition users.

❌ Non-Compliant Implementation
<button aria-label="Submit credit details">Pay Now</button>
✓ Remediation Code (Tailwind/HTML)
<button aria-label="Pay Now and submit credit details">Pay Now</button>
Rule 10 - custom-motion-preference-check

Animation Lacks Reduced Motion Query

LowSC 2.3.3 (Animation from Interactions) - Level AAA

Identifies CSS animations lacking @media (prefers-reduced-motion) wrappers for vestibular motion sensitivity.

❌ Non-Compliant Implementation
.animated-hero { animation: spin 2s infinite; }
✓ Remediation Code (Tailwind/HTML)
@media (prefers-reduced-motion: no-preference) { .animated-hero { animation: spin 2s infinite; } }
Rule 11 - custom-autoplay-media

Autoplay Sound / Video Block

HighSC 1.4.2 (Audio Control) - Level A

Flags audio or video elements configured to autoplay sound. Autoplay audio overrides screen reader voices.

❌ Non-Compliant Implementation
<video src="/assets/intro.mp4" autoplay></video>
✓ Remediation Code (Tailwind/HTML)
<video src="/assets/intro.mp4" controls></video>
Rule 12 - custom-video-captions-missing

Video Component Lacks Subtitles/Captions

HighSC 1.2.2 (Captions - Prerecorded) - Level A

Flags video player elements that do not contain a child <track kind="captions"> or <track kind="subtitles"> node.

❌ Non-Compliant Implementation
<video controls src="/assets/intro.mp4"></video>
✓ Remediation Code (Tailwind/HTML)
<video controls src="/assets/intro.mp4"><track default kind="captions" srclang="en" src="/captions_en.vtt"></video>
Rule 13 - custom-vague-link-text
MediumSC 2.4.4 (Link Purpose) - Level A

Flags links labeled with generic terms like "click here", "read more", or "learn more".

❌ Non-Compliant Implementation
<a href="/docs/api">Click Here</a> to view docs.
✓ Remediation Code (Tailwind/HTML)
<a href="/docs/api">View the API Documentation</a>.
Rule 14 - custom-skip-link-missing
MediumSC 2.4.1 (Bypass Blocks) - Level A

Flags pages with navigation headers or sidebars that lack a hidden skip bypass link as the first focusable child.

❌ Non-Compliant Implementation
<body><nav><!-- menu --></nav><main id="main-content">
✓ Remediation Code (Tailwind/HTML)
<body><a href="#main-content" class="sr-only focus:not-sr-only">Skip to Main Content</a><nav></nav><main id="main-content">
Rule 15 - custom-skip-link-advisory
LowSC 2.4.1 (Bypass Blocks) - Level A

Verifies existing skip link targets resolve to valid focusable DOM elements on the page.

❌ Non-Compliant Implementation
<a href="#non-existent">Skip</a>
✓ Remediation Code (Tailwind/HTML)
<a href="#main-content">Skip to Main Content</a>
Rule 16 - custom-theme-persistence

Dark/Light Theme Toggle State

LowSC 1.4.11 (Non-text Contrast) - Level AA

Audits theme switcher controls for proper aria-pressed state attributes and theme contrast.

❌ Non-Compliant Implementation
<button onclick="toggleTheme()">Theme</button>
✓ Remediation Code (Tailwind/HTML)
<button aria-pressed="true" aria-label="Toggle dark theme" onclick="toggleTheme()">Theme</button>
Rule 17 - custom-pdf-accessibility

Scanned or Untagged PDF Document Link

MediumSC 1.1.1 (Non-text Content) - Level A

Scans page PDF link destinations via Web Worker to detect scanned image-only PDFs lacking text layers.

❌ Non-Compliant Implementation
<a href="/scanned-contract.pdf">Download Agreement</a>
✓ Remediation Code (Tailwind/HTML)
<a href="/accessible-contract.pdf">Download Accessible PDF Agreement (Text-Searchable)</a>
Rule 18 - custom-governance-statement

Accessibility Statement Missing in Footer

LowSC 3.1.1 (Language of Page) - Level A

Audits global page footer for presence of an explicit link to an Accessibility Statement page.

❌ Non-Compliant Implementation
<footer><a href="/privacy">Privacy</a></footer>
✓ Remediation Code (Tailwind/HTML)
<footer><a href="/privacy">Privacy</a> <a href="/accessibility">Accessibility Statement</a></footer>
Rule 19 - custom-decorative-image-alt

Decorative Image Has Non-Empty Alt Text

MediumSC 1.1.1 (Non-text Content) - Level A

Flags decorative images (role="presentation" or aria-hidden="true") that still contain a non-empty alt attribute.

❌ Non-Compliant Implementation
<img role="presentation" alt="Company Banner" src="banner.png" />
✓ Remediation Code (Tailwind/HTML)
<img role="presentation" alt="" src="banner.png" />
Rule 20 - custom-audio-description-missing

Video Lacks Audio Description Track

HighSC 1.2.5 (Audio Description) - Level AA

Flags video elements missing <track kind="descriptions"> for blind visual narration.

❌ Non-Compliant Implementation
<video src="tutorial.mp4" controls></video>
✓ Remediation Code (Tailwind/HTML)
<video src="tutorial.mp4" controls><track kind="descriptions" src="desc_en.vtt"></video>
Rule 21 - custom-audio-transcript-missing

Audio Content Missing Text Transcript

HighSC 1.2.1 (Audio-only) - Level A

Flags <audio> elements with no nearby text transcript link or aria-describedby reference.

❌ Non-Compliant Implementation
<audio src="podcast.mp3" controls></audio>
✓ Remediation Code (Tailwind/HTML)
<audio src="podcast.mp3" controls></audio><a href="/transcripts/podcast-1.html">Read Transcript</a>
Rule 22 - custom-color-alone-required

Required Field Indicated by Color Alone

MediumSC 1.4.1 (Use of Color) - Level A

Flags required form fields that rely on red color styling alone without a visible asterisk (*), text label, or aria-required attribute.

❌ Non-Compliant Implementation
<label class="text-red-500">Email <input type="email" required /></label>
✓ Remediation Code (Tailwind/HTML)
<label>Email <span class="text-red-500">*</span> <input type="email" required aria-required="true" /></label>
Rule 23 - custom-images-of-text

Image Appears to Contain Styled Text

MediumSC 1.4.5 (Images of Text) - Level AA

Flags images whose alt text is a full sentence (>30 chars), indicating text baked into images instead of HTML.

❌ Non-Compliant Implementation
<img alt="Special Offer 50% Off Everything Today Only Click Now" src="banner.png" />
✓ Remediation Code (Tailwind/HTML)
<div class="bg-indigo-600 text-white p-6 font-bold text-2xl">Special Offer 50% Off Everything</div>
Rule 24 - custom-title-attribute-advisory

Title Attribute Advisory on Controls

LowSC 1.3.1 (Info and Relationships) - Level A

Flags usage of native title tooltips on interactive elements which are inaccessible on touch devices.

❌ Non-Compliant Implementation
<button title="Deletes item from cart">Remove</button>
✓ Remediation Code (Tailwind/HTML)
<button aria-describedby="tooltip-1">Remove</button><div id="tooltip-1" role="tooltip">Deletes item</div>
Rule 25 - custom-sensory-characteristics

Instruction Relies on Shape or Position Alone

MediumSC 1.3.3 (Sensory Characteristics) - Level A

Audits page text for instructions that rely on visual shape, color, or location parameters alone (e.g. instructing users to select controls by color or position).

❌ Non-Compliant Implementation
<p>Click the green round button on the right to complete checkout.</p>
✓ Remediation Code (Tailwind/HTML)
<p>Select the "Complete Checkout" button to finish your order.</p>
Rule 26 - custom-page-title-missing

Page Title Missing

HighSC 2.4.2 (Page Titled) - Level A

Flags pages missing a top-level <title> element.

❌ Non-Compliant Implementation
<head></head>
✓ Remediation Code (Tailwind/HTML)
<head><title>Checkout - MyStore Official</title></head>
Rule 27 - custom-page-title-generic

Page Title Generic

HighSC 2.4.2 (Page Titled) - Level A

Flags pages with default titles like "Home", "Untitled Page", or "Document".

❌ Non-Compliant Implementation
<title>Home</title>
✓ Remediation Code (Tailwind/HTML)
<title>Dashboard - A11yEngine Platform</title>
Rule 28 - custom-page-title-duplicate-h1

Page Title Duplicates H1 String

LowSC 2.4.2 (Page Titled) - Level A

Flags page titles that are identical copies of the main H1 heading without brand name context.

❌ Non-Compliant Implementation
<title>Contact Us</title>
✓ Remediation Code (Tailwind/HTML)
<title>Contact Us | A11yEngine Platform</title>
Rule 29 - custom-touch-target-size

Touch Target Too Small (<24×24px)

MediumSC 2.5.8 (Target Size Minimum) - Level AA

Flags interactive controls with bounding dimensions under 24×24 CSS px (WCAG 2.2 target size requirement).

❌ Non-Compliant Implementation
<button style="width:14px; height:14px;">x</button>
✓ Remediation Code (Tailwind/HTML)
<button style="min-width:24px; min-height:24px; padding:6px;">x</button>
Rule 30 - custom-auto-updating-marquee

Auto-Scrolling Marquee Without Pause

HighSC 2.2.2 (Pause, Stop, Hide) - Level A

Flags <marquee> elements or dynamic auto-scrolling containers lacking pause controls.

❌ Non-Compliant Implementation
<marquee>Breaking News Flash</marquee>
✓ Remediation Code (Tailwind/HTML)
<div class="carousel" data-pause="true"><button aria-label="Pause marquee">Pause</button></div>
Rule 31 - custom-meta-refresh

Meta Refresh Redirect Present

HighSC 2.2.1 (Timing Adjustable) - Level A

Flags <meta http-equiv="refresh"> elements that cause unannounced page reloads.

❌ Non-Compliant Implementation
<meta http-equiv="refresh" content="5;url=/login">
✓ Remediation Code (Tailwind/HTML)
// Perform server-side or user-initiated navigation instead
Rule 32 - custom-carousel-no-pause
MediumSC 2.2.2 (Pause, Stop, Hide) - Level A

Flags auto-rotating hero sliders lacking explicit pause/stop toggle buttons.

❌ Non-Compliant Implementation
<div class="slider-auto">...</div>
✓ Remediation Code (Tailwind/HTML)
<div class="slider"><button aria-label="Pause slider">Pause</button></div>
Rule 33 - custom-flashing-content

Flashing Animation Exceeds 3 Flashes/sec

CriticalSC 2.3.1 (Three Flashes) - Level A

Flags CSS animations with durations under 333ms, which can trigger seizures in photosensitive users.

❌ Non-Compliant Implementation
<div style="animation: flash 100ms infinite;">Notice</div>
✓ Remediation Code (Tailwind/HTML)
<div style="animation: pulse 2s ease-in-out infinite;">Notice</div>
Rule 34 - custom-drag-drop-no-keyboard-alt

Drag-and-Drop Has No Keyboard Alternative

HighSC 2.5.7 (Dragging Movements) - Level AA

Flags draggable="true" elements lacking keyboard reordering controls ("Move Up / Move Down").

❌ Non-Compliant Implementation
<div draggable="true">Item 1</div>
✓ Remediation Code (Tailwind/HTML)
<div draggable="true">Item 1 <button aria-label="Move item up">▲</button></div>
Rule 35 - custom-focus-indicator-quality

Focus Indicator Contrast Advisory

LowSC 2.4.13 (Focus Appearance) - Level AAA

Audits focus ring contrast against adjacent background colors.

❌ Non-Compliant Implementation
button:focus { outline: 1px solid #eee; }
✓ Remediation Code (Tailwind/HTML)
button:focus { outline: 2px solid #4f46e5; }
Rule 36 - custom-language-of-parts

Foreign Language Content Missing lang Attribute

MediumSC 3.1.2 (Language of Parts) - Level AA

Flags foreign-language text snippets on English pages missing explicit lang="..." attributes.

❌ Non-Compliant Implementation
<p>S'il vous plaît revoir ce document</p>
✓ Remediation Code (Tailwind/HTML)
<p lang="fr">S'il vous plaît revoir ce document</p>
Rule 37 - custom-auto-context-change

Select Input Triggers Automatic Context Change

HighSC 3.2.2 (On Input) - Level A

Flags <select> elements with onchange handlers that automatically submit forms on option pick.

❌ Non-Compliant Implementation
<select onchange="this.form.submit()"><option>1</option></select>
✓ Remediation Code (Tailwind/HTML)
<form><select><option>1</option></select><button type="submit">Go</button></form>
Rule 38 - custom-form-error-color-only

Form Error Indicated by Color Alone

HighSC 3.3.1 (Error Identification) - Level A

Flags form fields with red border error styling that lack text descriptions or aria-describedby references.

❌ Non-Compliant Implementation
<input class="border-red-500" />
✓ Remediation Code (Tailwind/HTML)
<input class="border-red-500" aria-describedby="err-1" aria-invalid="true" /><span id="err-1" class="text-red-600 text-xs">Enter valid email.</span>
Rule 39 - custom-empty-button

Empty Button Lacks Accessible Name (WAVE Parity)

CriticalSC 4.1.2 (Name, Role, Value) - Level A

Flags <button> elements with no inner text, aria-label, title, or image alt text.

❌ Non-Compliant Implementation
<button></button>
✓ Remediation Code (Tailwind/HTML)
<button aria-label="Close dialog">✕</button>
Rule 40 - custom-broken-aria-reference

Broken ARIA ID Reference (WAVE Parity)

HighSC 1.3.1 (Info and Relationships) - Level A

Flags aria-labelledby, aria-describedby, or aria-controls pointing to non-existent DOM element IDs.

❌ Non-Compliant Implementation
<input aria-describedby="missing-id" />
✓ Remediation Code (Tailwind/HTML)
<input aria-describedby="help-text" /><span id="help-text">Enter 8+ chars.</span>
Rule 41 - custom-skipped-heading-level

Non-Sequential Skipped Heading Level (WAVE Parity)

MediumSC 1.3.1 (Info and Relationships) - Level A

Flags heading structures that skip levels non-sequentially (e.g. H1 directly to H3).

❌ Non-Compliant Implementation
<h1>Main Title</h1>
<h3>Sub Header</h3>
✓ Remediation Code (Tailwind/HTML)
<h1>Main Title</h1>
<h2>Sub Header</h2>
Rule 42 - custom-redundant-link
LowSC 2.4.4 (Link Purpose) - Level A

Flags adjacent links pointing to the exact same href destination.

❌ Non-Compliant Implementation
<a href="/about"><img src="thumb.jpg" alt="" /></a> <a href="/about">About Us</a>
✓ Remediation Code (Tailwind/HTML)
<a href="/about"><img src="thumb.jpg" alt="" /> About Us</a>
Rule 43 - custom-noscript-element

Noscript Element Present (WAVE Parity)

LowSC 4.1.2 (Name, Role, Value) - Best Practice

Flags <noscript> tags whose content is hidden from JavaScript-enabled screen readers.

❌ Non-Compliant Implementation
<noscript>Enable JS to view this site.</noscript>
✓ Remediation Code (Tailwind/HTML)
<div role="alert">JavaScript is recommended.</div>