@codelaw/rules-html · codelaw-rules-html
codelaw's rules for HTML — one of the first-party rule packs
(SR-RULE-PACKS). The same files ship on npm
as @codelaw/rules-html and on PyPI as codelaw-rules-html.
# codelaw.toml
extends = ["codelaw:html/recommended"]
preview = true # every rule is `preview` until a corpus run promotes it
Presets
| preset | rules | ported from |
|---|---|---|
html/recommended |
64 | html-validate 11.16.4 html-validate:recommended, without its layout rules and without the cosmetic rules its prettier and browser presets switch off (see below) |
html/a11y |
26 | html-validate 11.16.4 html-validate:a11y: every rule it turns on |
html/document |
5 | html-validate 11.16.4 html-validate:document: checks that only make sense for a complete page |
html/conventions |
3 | opt-in: the starter rule html/target-blank-rel, and HTMLHint's inline-style-disabled and inline-script-disabled |
html/security |
5 | the html pack's security rules: subresource integrity, reverse tabnabbing, inline scripts, password autocomplete, meta refresh; codelaw:sec-html/recommended extends it |
html/size |
1 | Size limits for pages and templates, opt-in: a line limit per file |
html/a11y is a subset of html/recommended, as upstream; turn it on alone
for an accessibility-only check. html/document adds to html/recommended.
html/security gathers the pack's five security rules so that
codelaw:sec-html/recommended (the security-html pack) can extend it
instead of copying them.
Every rule is reimplemented, not vendored: the checks, messages and docs are
written fresh, and each rule's ported_from: names the source rule. Every rule
is a native: rule, sharing one model of the document
(crates/codelaw-native/src/html_dom.rs): tree-sitter-html knows only a few of
HTML's implied end tags, so the model rebuilds the element tree the way a
browser (and html-validate) does, from the element table in data/.
Fix classes: 10 auto, 11 suggest, 51 manual.
Rules
| rule | fix | ported from | presets |
|---|---|---|---|
html/area-alt |
manual | html-validate/area-alt | recommended, a11y |
html/aria-hidden-body |
suggest | html-validate/aria-hidden-body | recommended, a11y |
html/aria-label-misuse |
manual | html-validate/aria-label-misuse | recommended, a11y |
html/attribute-allowed-values |
manual | html-validate/attribute-allowed-values, htmlhint/src-not-empty | recommended |
html/attribute-misuse |
manual | html-validate/attribute-misuse | recommended |
html/autocomplete-password |
manual | html-validate/autocomplete-password | recommended, security |
html/button-type |
suggest | html-validate/no-implicit-button-type, htmlhint/button-type-require | recommended, a11y |
html/close-attr |
auto | html-validate/close-attr | recommended |
html/close-order |
manual | html-validate/close-order, htmlhint/tag-pair | recommended |
html/deprecated |
manual | html-validate/deprecated, htmlhint/tag-no-obsolete | recommended |
html/doctype-html |
suggest | html-validate/doctype-html, htmlhint/doctype-html5 | recommended |
html/element-name |
manual | html-validate/element-name | recommended |
html/element-permitted-content |
manual | html-validate/element-permitted-content | recommended |
html/element-permitted-occurrences |
manual | html-validate/element-permitted-occurrences | recommended |
html/element-permitted-order |
manual | html-validate/element-permitted-order | recommended |
html/element-permitted-parent |
manual | html-validate/element-permitted-parent | recommended |
html/element-required-ancestor |
manual | html-validate/element-required-ancestor | recommended |
html/element-required-attributes |
manual | html-validate/element-required-attributes, htmlhint/html-lang-require | recommended |
html/element-required-content |
manual | html-validate/element-required-content, htmlhint/title-require | recommended |
html/empty-heading |
manual | html-validate/empty-heading | recommended, a11y |
html/empty-title |
manual | html-validate/empty-title | recommended, a11y |
html/fieldset-legend |
manual | html-validate/wcag/h71 | recommended, a11y |
html/form-dup-name |
manual | html-validate/form-dup-name | recommended |
html/form-submit |
manual | html-validate/wcag/h32 | recommended, a11y |
html/hidden-focusable |
manual | html-validate/hidden-focusable | recommended, a11y |
html/img-alt |
manual | html-validate/wcag/h37, htmlhint/alt-require | recommended, a11y |
html/img-title |
manual | html-validate/wcag/h67 | recommended, a11y |
html/input-attributes |
suggest | html-validate/input-attributes | recommended |
html/input-image-alt |
manual | html-validate/wcag/h36 | recommended, a11y |
html/link-text |
manual | html-validate/wcag/h30 | recommended, a11y |
html/long-title |
manual | html-validate/long-title | recommended |
html/map-dup-name |
manual | html-validate/map-dup-name | recommended |
html/map-id-name |
manual | html-validate/map-id-name | recommended |
html/meta-refresh |
manual | html-validate/meta-refresh | recommended, a11y, security |
html/multiple-labeled-controls |
manual | html-validate/multiple-labeled-controls | recommended, a11y |
html/no-abstract-role |
manual | html-validate/no-abstract-role | recommended, a11y |
html/no-autoplay |
suggest | html-validate/no-autoplay | recommended, a11y |
html/no-conditional-comment |
manual | html-validate/no-conditional-comment | recommended |
html/no-deprecated-attr |
manual | html-validate/no-deprecated-attr | recommended |
html/no-dup-attr |
auto | html-validate/no-dup-attr, htmlhint/attr-no-duplication | recommended |
html/no-dup-class |
auto | html-validate/no-dup-class | recommended |
html/no-duplicate-id |
manual | html-validate/no-dup-id, htmlhint/id-unique | recommended, a11y |
html/no-implicit-close |
suggest | html-validate/no-implicit-close | recommended |
html/no-implicit-input-type |
suggest | html-validate/no-implicit-input-type | recommended |
html/no-multiple-main |
manual | html-validate/no-multiple-main | recommended |
html/no-utf8-bom |
manual | html-validate/no-utf8-bom | recommended |
html/no-raw-characters |
auto | html-validate/no-raw-characters, htmlhint/spec-char-escape | recommended |
html/no-redundant-aria-label |
auto | html-validate/no-redundant-aria-label | recommended, a11y |
html/no-redundant-for |
auto | html-validate/no-redundant-for | recommended, a11y |
html/no-redundant-role |
auto | html-validate/no-redundant-role | recommended, a11y |
html/prefer-button |
manual | html-validate/prefer-button | recommended |
html/prefer-native-element |
manual | html-validate/prefer-native-element | recommended, a11y |
html/prefer-tbody |
auto | html-validate/prefer-tbody | recommended |
html/script-element |
suggest | html-validate/script-element | recommended |
html/script-type |
auto | html-validate/script-type | recommended |
html/tel-non-breaking |
suggest | html-validate/tel-non-breaking | recommended |
html/text-content |
manual | html-validate/text-content | recommended, a11y |
html/th-scope |
manual | html-validate/wcag/h63 | recommended, a11y |
html/unique-landmark |
manual | html-validate/unique-landmark | recommended, a11y |
html/unrecognized-char-ref |
manual | html-validate/unrecognized-char-ref | recommended |
html/valid-autocomplete |
manual | html-validate/valid-autocomplete | recommended, a11y |
html/valid-for |
manual | html-validate/valid-for | recommended |
html/valid-id |
manual | html-validate/valid-id | recommended |
html/void-content |
suggest | html-validate/void-content | recommended |
html/heading-level |
manual | html-validate/heading-level | document |
html/input-missing-label |
manual | html-validate/input-missing-label, htmlhint/input-requires-label | document |
html/missing-doctype |
suggest | html-validate/missing-doctype | document |
html/no-missing-references |
manual | html-validate/no-missing-references | document |
html/require-sri |
manual | html-validate/require-sri | document, security |
html/target-blank-rel |
auto | — (starter rule) | conventions, security |
html/no-inline-style |
manual | html-validate/no-inline-style, htmlhint/inline-style-disabled | conventions |
html/no-inline-script |
manual | htmlhint/inline-script-disabled | conventions, security |
The four starter-catalogue rules (SR-RULE-PACKS
decision 8): html/img-alt (↔ wcag/h37), html/no-duplicate-id (↔ no-dup-id)
and html/button-type (↔ no-implicit-button-type) match html-validate rules
and sit in html/recommended; html/target-blank-rel matches none and forms
html/conventions. The other ported rules keep html-validate's names, except
its WCAG technique rules, which are named for what they check
(wcag/h30 → html/link-text, h32 → form-submit, h36 → input-image-alt,
h63 → th-scope, h67 → img-title, h71 → fieldset-legend).
Not ported, and why
| upstream rule | why |
|---|---|
html-validate attr-case, element-case |
never: layout — case-only style belongs to the formatter |
html-validate attr-delimiter, attr-spacing, no-trailing-whitespace |
never: layout — whitespace belongs to the formatter |
html-validate attr-quotes, doctype-style |
never: layout — quoting and the doctype's case belong to the formatter (also switched off by its prettier preset) |
html-validate attribute-boolean-style, attribute-empty-style, void-style, no-self-closing |
never: cosmetic — how disabled, alt="" and void tags are spelled is the formatter's call (switched off by its browser and prettier presets) |
html-validate deprecated-rule, no-unused-disable |
about html-validate's own configuration and inline directives; codelaw reports its own |
html-validate svg-focusable |
switched off in every upstream preset (it only matters for Internet Explorer) |
html-validate no-inline-style in recommended |
moved to the opt-in html/conventions: its browser preset switches it off, and it is a style policy, not a correctness check |
HTMLHint attr-lowercase, tagname-lowercase, attr-value-double-quotes, attr-value-single-quotes, attr-whitespace, attr-no-unnecessary-whitespace, space-tab-mixed-disabled, tag-self-close, empty-tag-not-self-closed, attr-sorted |
never: layout |
HTMLHint head-script-disabled, script-disabled, style-disabled, id-class-ad-disabled, id-class-value, href-abs-or-rel, attr-unsafe-chars, attr-value-not-empty, attr-value-no-duplication, tagname-specialchars, tags-check |
house policy without a correctness reason, or covered by a ported rule (tags-check by the content-model rules, tagname-specialchars by html/element-name) |
HTMLHint h1-require, main-require, meta-charset-require, meta-description-require, meta-viewport-require, link-rel-canonical-require, frame-title-require, form-method-require |
page-level SEO or policy checks html-validate's presets don't have; candidates for a later html/strict |
How the ports differ
| rule | difference |
|---|---|
| all | the document model is rebuilt from tree-sitter-html's tokens with html-validate's implied-end-tag and implied-element rules; markup tree-sitter can't parse at all (a raw < in text) is treated as text |
| all | attribute values holding template code ({{ }}, <% %>, ${ }, {% %}) are treated as unknown and not checked, as html-validate does for its framework transforms |
html/element-permitted-content |
obsolete elements are left to html/deprecated instead of being reported again wherever they appear |
html/close-order |
reports unclosed elements and stray end tags; html-validate also reports the end tag that closed past them, which repeats the first finding |
html/missing-doctype |
only files with an <html> element are checked; fragments and partials are not documents |
html/no-implicit-close |
the suggest fix writes the end tag after the element's last content |
html/prefer-tbody |
the fix wraps the rows when they are next to each other; otherwise the rule only reports |
html/heading-level |
sectioning roots are matched by tag or [attr="value"] selectors only |
html/require-sri |
no include/exclude URL options yet |
html/no-utf8-bom |
manual: the mark is in the file's bytes, outside the text a fix edits; only the file itself is checked, not an HTML region of another file |
Data
| table | source |
|---|---|
data/html/elements.json |
html-validate 11.16.4's html5 element metadata (MIT): content categories, content models, permitted parents and order, required and deprecated attributes, attribute value enumerations, implied end tags, ARIA implicit roles. Its JavaScript callbacks are rewritten as JSON conditions ({"attr": "href"}, {"ancestor": ["map"]}, {"if": …, "then": …, "else": …}) that html_dom.rs evaluates. |
data/html/entities.json |
the named character references html-validate 11.16.4 ships (MIT), following the WHATWG table |
data/html/input-attributes.json |
which <input> types each attribute applies to, from html-validate 11.16.4's input-attributes rule (MIT) |
See NOTICE.
Upstream versions
- html-validate 11.16.4 (MIT) — presets
recommended,a11y,document,prettier,browser; rule docs at https://html-validate.org/rules/. - HTMLHint 1.9.2 (MIT) — cross-checked for rules html-validate lacks.
Metadata
Release files for codelaw-rules-html 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| codelaw_rules_html-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for codelaw_rules_html-0.4.0-py3-none-any.whl |
Release files / codelaw_rules_html-0.4.0-py3-none-any.whl
| Download URL | codelaw_rules_html-0.4.0-py3-none-any.whl |
|---|---|
| Size | 92.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
23ed0db69243d37def0ed17f126ba3713e84071e39d93d20c8f2b0d406f64ba6
|
|
BLAKE2b-256 checksum How to use checksums |
122609fdeaa29347cda740c2e9cb52b876c33d9bf4c1f5aeea5c9466a8aabd6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for codelaw-rules-html 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
1 file in this release has been uploaded with provenance metadata.
Attestation for codelaw_rules_html-0.4.0-py3-none-any.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.