How this check works
Scanaris analyses the HTML your page serves, without running JavaScript or opening a browser, and runs eight accessibility tests that can be decided with certainty from the code. Three are medium severity: that the <html> tag declares the language with lang, that the <meta name="viewport"> exists, and that no form field (input, select, textarea, excluding hidden ones and buttons) lacks an accessible label, meaning it has a <label for>, sits inside a <label>, or carries aria-label, aria-labelledby or title. The other five are low severity: images without an alt attribute (an empty alt="" is valid for decorative ones; what fails is the attribute not existing), links with href and buttons with no text, no aria-label and no image with alt inside, repeated id attributes, elements with tabindex greater than zero, and empty h1 to h6 headings. Each failing test opens its own finding with the count.
Why it matters
Around 15% of the population has some disability, and many more people use the web with a screen reader, keyboard only or maximum zoom at particular moments. For them, an image without alt is a gap, a field without a label is a box with no clue what goes in it, and an icon-only button is announced as "button" and nothing else. Beyond ethics, it is law: the European Accessibility Act has applied since June 2025 to most digital services from businesses, and in the United States lawsuits over inaccessible websites number in the thousands per year. And it is SEO: alt, language and heading structure are exactly what Google reads.
How to fix it
- Language:
<html lang="en">. In Nuxt it is set inapp.head.htmlAttrsor by the i18n module; in Next.js, on the<html>of the root layout; in WordPress,language_attributes()in the theme writes it. - Viewport:
<meta name="viewport" content="width=device-width, initial-scale=1">. Withoutmaximum-scale=1oruser-scalable=no, which block zoom. - Form labels: one
<label for="email">per field with itsid, or the field inside the<label>. If the design shows no visible label,aria-label="Email address". Theplaceholderdoes not count: it disappears as you type. - Images: descriptive
alton informative ones ("Third-quarter sales chart"),alt=""on decorative ones. The Nuxt and Next.js image components require the attribute. - Icon links and buttons:
aria-label="Open menu", or visually hidden text with ansr-onlyclass. Inline SVG icons getaria-hidden="true". - Duplicate ids: usually come from repeated components with a hard-coded id. Derive the id from a prop or use
useId(). - Positive tabindex: change them to
0and order the elements in the HTML in the order they should be traversed. - Empty headings: if they were there for layout, change them to a
div; if they hold an icon, give them text.
Check it is fixed
curl -s https://yourdomain.com | grep -oE '<html[^>]*>|<meta name="viewport"[^>]*>'
curl -s https://yourdomain.com | grep -oE '<img[^>]*>' | grep -vc 'alt='
The first should show lang and the viewport; the second should give 0. For the rest, Chrome's Lighthouse panel (Accessibility tab) or the axe DevTools extension list each element with its selector.
Frequently asked questions
Does passing these eight tests mean my site is accessible?
No. They are the eight that can be checked with certainty without a browser. Colour contrast, visible focus, real reading order and JavaScript-built components need a review with browser tools and, for anything serious, a human audit. Passing them does mean you are not making the most frequent and most easily avoided mistakes.
My app is a SPA and the initial HTML is almost empty.
Then the check sees little, and so does Google. It is one more reason to server-render at least the main content; content without JavaScript explains it.
Why is an empty alt correct but a missing alt is not?
Because alt="" tells the screen reader "skip this image, it is decorative", whereas with no attribute the reader reads the file name, which is usually something like IMG_4821.jpg. Heading structure, which affects screen-reader navigation, is also reviewed by headings.