TagCheck

One command that finds semantic and accessibility mistakes in HTML, for people, CI, and AI agents.

Install and run Guide for AI agents

What it finds

TagCheck reads HTML files and reports mistakes a person would notice by looking at the page, or by using it with a keyboard or a screen reader.

It works on any HTML page, with or without TagBrush.css and TagAction.

page.html:12:3  error    missing-alt        <img src="photo.jpg"> needs alt text (alt="" if it's decorative)
page.html:20:3  error    broken-reference   aria-controls="menu" on <button> points to an id that doesn't exist
page.html:26:3  warning  unknown-class      class="hero" isn't part of TagBrush.css or TagAction: semantic HTML usually does the job
1 file checked: 2 errors, 1 warning

Install and run

You need Node.js 20 or later. Run it with npx on files or folders:

npx @kovirlabs/tagcheck page.html

Get a machine-readable report for agents and CI:

npx @kovirlabs/tagcheck site/ --json

Also check contrast and phone width in a real browser. This needs Playwright:

npm install -D playwright && npx playwright install chromium
npx @kovirlabs/tagcheck page.html --browser

With --browser, pages that link TagBrush.css or TagAction from jsDelivr get the copy installed in your project, if there is one. The check then works offline and tests your version. A stylesheet or script that still doesn't load is reported as not-loaded.

Options

--json
Print the report as JSON.
--browser
Also render each page in Chromium to check contrast and sideways scrolling.
--strict
Fail (exit code 1) on warnings too.
--ignore=a,b
Skip these rules.
--rules
List every rule.
--version
Print the version.
npx @kovirlabs/tagcheck site/ --strict
npx @kovirlabs/tagcheck page.html --ignore=inline-style,style-block

Exit codes

CodeMeaning
0Clean.
1Problems to fix. Errors only, or warnings too with --strict.
2Bad usage, such as no files given.

In CI

- run: npx @kovirlabs/tagcheck site/ --strict

The JSON report

--json prints one object for all the files. browser says whether the --browser checks ran. Browser problems have line and column set to null.

{
  "tool": "tagcheck",
  "version": "0.1.1",
  "browser": false,
  "files": [
    {
      "file": "page.html",
      "problems": [
        {
          "line": 6,
          "column": 3,
          "level": "error",
          "rule": "missing-alt",
          "message": "<img src=\"photo.jpg\"> needs alt text (alt=\"\" if it's decorative)"
        },
        {
          "line": 7,
          "column": 13,
          "level": "warning",
          "rule": "heading-skip",
          "message": "<h4> follows <h2>: don't skip heading levels"
        }
      ]
    }
  ],
  "errors": 1,
  "warnings": 1
}

Rules

Errors fail the check. Warnings fail it only with --strict. Rules marked --browser run only with that option. The llms.txt guide explains each rule and its fix.

Every rule, as --rules lists them
RuleLevelWhat it reports
missing-langerror<html> has no lang attribute
missing-viewportwarningno viewport <meta>, so phones show a zoomed-out desktop page
multiple-mainerrormore than one visible <main>
missing-alterror<img> without alt text
unlabeled-fielderrorform field with no label, aria-label, or aria-labelledby
label-for-missingerror<label for> points to an id that does not exist
empty-buttonerror<button> with no text or aria-label
empty-linkerror<a href> with no text or aria-label
clickable-diverror<div> or <span> used as a button or link
heading-skipwarninga heading level is skipped (h2 to h4)
duplicate-iderrorthe same id is used more than once
broken-referenceerroraria-controls, commandfor, for, list, or similar points to a missing id
unknown-commanderrorcommand="…" is not a browser command or one TagAction handles
clone-targeterrorcommand="--clone" must point at a <template>
remember-needs-idwarning<details> under data-tag-remember has no id, so its state is not saved
unknown-classwarninga class the Tag family does not document
unknown-attributewarninga data-tag… (or TagBrush) attribute or value the Tag family does not document
generated-markupwarningmarkup TagAction generates (data-tag="…") was copied into the source
inline-stylewarninginline style sets layout or colors instead of CSS variables
style-blockwarning<style> sets properties other than CSS variables
contrasterrortext below WCAG AA contrast (4.5:1) in the light or dark scheme (--browser)
overflowerrorthe page scrolls sideways at a phone width (--browser)
not-loadedwarninga stylesheet or script did not load, so the browser checks measured the page without it (--browser)

For AI agents

An agent that can't look at a screen can still run a command. TagCheck gives it the same feedback a person gets from looking at the page.

  1. Write the page.
  2. Run npx @kovirlabs/tagcheck page.html --json. Add --browser if Playwright is installed.
  3. For each problem, fix the HTML at line and column as the message says. Don't silence rules with --ignore unless the user asks.
  4. Run it again until errors is 0.

Give your agent TagCheck's llms.txt. It lists every rule and its fix. The family guide says how TagBrush.css, TagAction, and TagCheck fit together.

From code

Import check for one HTML string, or checkFiles for files and folders.

import { check, checkFiles } from '@kovirlabs/tagcheck';

check('<img src="a.png">');                        // [{ line, column, level, rule, message }, …]
await checkFiles(['site/'], { browser: true });    // the same report as --json

checkFiles(paths, { browser, ignore }) takes files and folders. It skips dot folders and node_modules. ignore is a list of rule names to skip.