Accessibility audit rules: WCAG and ARIA checks
Audit rules for accessibility: accessible names, ARIA roles and attributes, forms, headings and landmarks, tables, language and zoom on every crawled page.
squirrelscan runs its accessibility rules against every page it crawls. They cover accessible names for buttons, links and form controls, ARIA roles and attributes, heading and landmark structure, tables, language declarations and viewport settings. Each page below quotes the exact report message a rule emits, and most findings identify the offending element by selector, id or quoted text, so a coding agent can go straight to the markup that needs changing.
Run only these rules
squirrel audit https://example.com --rule-include a11yWhere to start
These carry the highest severity and weight in the category.
- aria-hidden on body or html: what it breaks: aria-hidden=true on the body or html element asks assistive technology to ignore the entire page. squirrel checks both, at the highest weight.
- Accessible names for buttons: what counts and how to check: A button with only an icon has no name for a screen reader. squirrel lists every button on every page that has nothing to announce.
- ARIA references pointing at duplicate or missing ids: aria-labelledby resolving to two elements, or to none, names the wrong thing silently. squirrel checks all eight ARIA id references.
- Dropdowns with no accessible name: naming a select: A select announced only as ‘combo box’ gives no clue what it changes. squirrel checks every select element on the page.
- input type=image without alt: an unnamed submit button: An image input is a submit button drawn as a picture, and with no alt it announces nothing. squirrel checks every one on the page.
Rules
| Rule | What it flags | Severity | Scope |
|---|---|---|---|
| Accessible name for a meter element and role=meter | A gauge that announces only a number tells a screen reader user nothing. squirrel checks native meter elements and role=meter. | error | Per-page |
| Accessible name for a progress bar and role=progressbar | A progress bar with no name announces a percentage and nothing else. squirrel checks native progress elements and role=progressbar. | error | Per-page |
| Accessible names for buttons: what counts and how to check | A button with only an icon has no name for a screen reader. squirrel lists every button on every page that has nothing to announce. | error | Per-page |
| accesskey: why duplicate shortcuts break and how to check | Two elements claiming the same accesskey means one shortcut is unreachable. squirrel lists every duplicated access key on every page. | warning | Per-page |
| ARIA attributes that are not allowed on an element | role=presentation with an aria-label, or a decorative image with one, contradicts itself. squirrel reports both on every page. | warning | Per-page |
| ARIA references pointing at duplicate or missing ids | aria-labelledby resolving to two elements, or to none, names the wrong thing silently. squirrel checks all eight ARIA id references. | error | Per-page |
| ARIA roles that require a particular parent role | role=listitem outside a list, or a tab outside a tablist, loses its meaning. squirrel checks explicit roles and native li, tr, td and option. | error | Per-page |
| ARIA roles that require particular child roles | role=list with no listitem, or role=tablist with no tab, is an incomplete widget. squirrel checks thirteen container roles for their children. | error | Per-page |
| aria-hidden on body or html: what it breaks | aria-hidden=true on the body or html element asks assistive technology to ignore the entire page. squirrel checks both, at the highest weight. | error | Per-page |
| aria-label: which elements need one and how to check | Buttons, links and inputs with no visible text and no aria-label have no name for screen readers. squirrel finds every one on every page. | error | Per-page |
| autocomplete: the right token for every form field | Name, email, address and payment fields with a missing or wrong autocomplete token break autofill. squirrel finds every one on every page. | warning | Per-page |
| Checkboxes, radios and switches with no accessible name | A checkbox that announces only its role gives no reason to tick it. squirrel checks toggle roles and native checkbox and radio inputs. | error | Per-page |
| Color contrast: the 4.5:1 rule and how to check it | Light gray text on white fails WCAG AA. squirrel measures the contrast of text whose color and background are both set inline, and reports pairs under 4.5:1. | warning | Per-page |
| Command roles: buttons, links and menu items need names | Anything that performs an action has to announce what it does. squirrel lists every command element on a page with no accessible name. | error | Per-page |
| Definition list structure: what belongs inside a dl | A stray paragraph between the terms of a dl breaks the pairing screen readers rely on. squirrel checks every definition list on the page. | error | Per-page |
| Deprecated and abstract ARIA roles, and what to use instead | role=directory is deprecated and abstract roles were never meant for markup. squirrel names every one it finds and its replacement. | error | Per-page |
| Dialog accessible name: role=dialog and the dialog element | A modal with no name leaves screen reader users guessing what just opened. squirrel checks ARIA dialogs and native dialogs separately. | error | Per-page |
| Dropdowns with no accessible name: naming a select | A select announced only as ‘combo box’ gives no clue what it changes. squirrel checks every select element on the page. | error | Per-page |
| dt and dd outside a dl: orphaned definition list items | A dt or dd that is not inside a dl loses the term-description pairing entirely. squirrel finds every orphan on every page. | error | Per-page |
| Duplicate id on a focusable element: what it breaks | Two inputs sharing an id break label association and focus management. squirrel checks every focusable element that carries an id. | error | Per-page |
| Empty headings: what counts as empty and how to check | A heading with no text still shows up in the screen reader outline, as a blank entry. squirrel flags every one on every page. | warning | Per-page |
| focus-visible: keeping a visible keyboard focus ring | Removing the focus outline leaves keyboard users with no idea where they are. squirrel flags outline:none with no :focus-visible fallback. | warning | Per-page |
| Focusable elements inside aria-hidden: the tab trap | A hidden element that still takes focus lets keyboard users tab into nothing. squirrel finds them, and tells anti-spam honeypots apart. | error | Per-page |
| Form labels: which inputs need one and how to check | An input labelled only by its placeholder loses its label the moment someone types. squirrel lists every unlabeled input, textarea and select. | error | Per-page |
| Heading order: why skipping from h1 to h3 matters | Screen reader users navigate by heading level, and a skipped level makes the outline harder to follow. squirrel checks document order on every page. | warning | Per-page |
| html lang: valid values and what a missing one breaks | Without a lang attribute a screen reader guesses the pronunciation, often wrongly. squirrel checks the html element on every page. | error | Per-page |
| Identical link text pointing at different pages | Two links reading ‘Learn more’ that go to different places are indistinguishable in a screen reader’s link list. squirrel finds them. | warning | Per-page |
| iframe title: naming embedded frames for screen readers | An iframe with no title is announced as just ‘frame’. squirrel checks every iframe and frame element on the page. | error | Per-page |
| Input fields with no accessible name, ARIA and native | Text boxes, comboboxes and sliders that announce nothing. squirrel checks the nine ARIA input roles alongside native inputs and selects. | error | Per-page |
| Input type, enterkeyhint and novalidate on forms | type=text where type=email belongs costs mobile users the right keyboard. squirrel checks three ways a form opts out of browser help. | warning | Per-page |
| input type=image without alt: an unnamed submit button | An image input is a submit button drawn as a picture, and with no alt it announces nothing. squirrel checks every one on the page. | error | Per-page |
| Inputs that block paste, and why that fails users | Blocking paste forces people to retype passwords by hand. squirrel finds onpaste, oncopy and oncut handlers that cancel the event. | warning | Per-page |
| Invalid ARIA attribute values and the types they need | aria-checked=yes and aria-level=two are ignored by browsers. squirrel type-checks 26 ARIA attributes against their allowed values. | error | Per-page |
| Invalid ARIA role values and how to check them | A misspelled or invented role gives an element no semantics at all. squirrel validates every role attribute against the ARIA vocabulary. | error | Per-page |
| Invalid aria-* attribute names, aria-labeledby included | A misspelled ARIA attribute is ignored by every browser and warns nobody. squirrel checks each aria-* name against the ARIA vocabulary. | error | Per-page |
| Landmark regions: main, nav and footer on every page | Screen reader users jump between landmarks instead of reading top to bottom. squirrel reports which of the three a page has. | info | Per-page |
| lang and xml:lang disagreeing on the html element | When both attributes are present and name different languages, a screen reader can pick the wrong voice. squirrel compares them. | error | Per-page |
| lang on elements below html: validating every tag | A quoted passage marked with a bad lang tag is read in the wrong voice. squirrel validates every lang attribute except the one on html. | warning | Per-page |
| Link text: why ‘click here’ fails and what to use | Links reading ‘click here’, and links wrapping an unlabeled icon, give screen reader users nothing to go on. squirrel lists both kinds. | warning | Per-page |
| Links in a paragraph told apart by color alone | A link inside body text needs more than color to be visible. squirrel flags links whose markup removes the underline. | warning | Per-page |
| meta http-equiv=refresh: redirects and auto-refresh | A timed redirect moves the page out from under a screen reader user mid-sentence. squirrel reads the content value and grades it. | error | Per-page |
| object elements with no alternative content | An embedded object with no fallback is announced as nothing at all. squirrel checks every object element on the page. | warning | Per-page |
| One control, two labels: why multiple labels confuse | A control with two labels is announced inconsistently across screen readers. squirrel counts the labels on every input on the page. | warning | Per-page |
| One main landmark per page, and what happens without | A page with no main landmark, or with two, breaks the jump-to-content shortcut screen reader users rely on. squirrel counts them. | warning | Per-page |
| Orphaned li: list items outside ul, ol or menu | An li whose parent is not a list is announced as a plain block of text. squirrel checks the immediate parent of every list item. | error | Per-page |
| Positive tabindex and why it breaks the tab order | tabindex=1 pulls an element to the front of the tab order for the entire page. squirrel flags every positive value on every page. | warning | Per-page |
| Redundant alt text: image of, filenames and captions | Screen readers already announce that it is an image, so alt starting with ‘photo of’ wastes the announcement. squirrel checks four ways. | warning | Per-page |
| Required ARIA attributes for a role, and what is missing | role=checkbox with no aria-checked has a state screen readers cannot read. squirrel checks the roles whose attributes are mandatory. | error | Per-page |
| role=text with focusable children: why it breaks | role=text flattens a subtree into one announced string, so a link inside it cannot be operated. squirrel reports every case it finds. | warning | Per-page |
| role=tooltip with no content: what to check | A tooltip with nothing to announce leaves the control it explains unexplained. squirrel checks every role=tooltip element on the page. | error | Per-page |
| role=treeitem: naming every node in a tree | A tree node that announces only its position in the tree is unusable. squirrel checks every role=treeitem for something to read out. | error | Per-page |
| Skip to content: bypassing repeated navigation | Keyboard users tab through the whole navigation on every page without a bypass. squirrel accepts a skip link or landmark structure. | warning | Per-page |
| Table headers: why a data table needs th cells | A table built from styled td cells has no header relationships for a screen reader. squirrel checks every data table for th elements. | warning | Per-page |
| Tables sharing a name, and tables with none | Several tables on one page need distinct names or a screen reader’s table list is unusable. squirrel checks captions and labels. | warning | Per-page |
| td headers attribute pointing at a missing th id | A headers attribute naming an id that does not exist leaves the cell unassociated. squirrel checks every reference in every table. | error | Per-page |
| th cells with no data cells: a layout table in disguise | A header with no data in its row or column usually means the table is really a layout. squirrel builds the grid and checks each one. | warning | Per-page |
| Touch target size: the 24 and 44 pixel minimums | Buttons and links smaller than a fingertip are hard to hit on a phone. squirrel flags interactive elements sized below 44 pixels inline. | warning | Per-page |
| ul and ol with children that are not list items | A div between the li elements of a list changes what a screen reader announces. squirrel checks the direct children of every list. | error | Per-page |
| user-scalable=no: viewport settings that block zoom | A viewport that caps the zoom level stops low-vision users enlarging text. squirrel parses the viewport meta tag on every page. | error | Per-page |
| Video captions: track elements and embedded players | A video with no caption track excludes deaf and hard of hearing viewers. squirrel checks native video and flags third-party embeds. | warning | Per-page |
| Visible label missing from the accessible name | A button showing ‘Search’ with aria-label ‘Find products’ may not respond when a user speaks its visible label. squirrel compares the two. | error | Per-page |
Key terms
- Accessible name: The name assistive technology announces for an element, computed from its content, label, aria-label or aria-labelledby.
- Alt text: The alt attribute that gives an image a text alternative for screen readers, failed loads and search engines.
- Anchor text: The visible, clickable text of a link, which tells readers and search engines what the target is about.
- ARIA: Accessible Rich Internet Applications: roles, states and properties that describe custom widgets to assistive technology.
- Captions: Synchronised text of a video’s dialogue and sounds, supplied as a
<track kind="captions">file. - Client-side redirect: A redirect done in the page (meta refresh or JavaScript) rather than with an HTTP 3xx response.
- Color contrast ratio: The luminance ratio between text and its background; WCAG AA asks for 4.5:1 for body text and 3:1 for large text.
- Form labels: The
<label>or accessible name tied to each form control, plus autocomplete tokens, so people know what to enter. - Heading hierarchy: The nesting of h1 to h6 headings that gives a page its outline for readers, screen readers and parsers.
- Keyboard accessibility: Whether every control can be reached and used with a keyboard alone, with a visible focus indicator and sensible tab order.
- Landmark regions: The page regions (main, nav, header, footer) that screen reader users jump between, plus the skip link to main content.
- lang attribute: The lang attribute on
<html>(and on passages) that declares the language, so screen readers pick the right voice. - Touch target size: The tappable area of a control; WCAG 2.2 sets 24 by 24 CSS pixels as the AA minimum.
- Viewport meta tag:
<meta name="viewport">that sets the layout width to the device width; disabling zoom in it fails accessibility. - WCAG: The W3C’s Web Content Accessibility Guidelines, organised as testable success criteria at levels A, AA and AAA; 2.2 is current.
Related categories
Images checks that every image has an alt attribute. Mobile checks tap targets, font size and the viewport tag from the phone side, and Content checks the heading outline of each page.
Learn more
- Website audit tool
- Sample report, with the Accessibility section on a real site
Disable all Accessibility rules
[rules]
disable = ["a11y/*"]