LEARNING OBJECTIVES โต
- Understand the architecture of HTMLHint as a lightweight, fast AST-free regex/tokenizer static analyzer.
- Construct a production-grade
.htmlhintrcconfiguration file enforcing enterprise style guides. - Configure critical rules:
tag-pair,id-unique,attr-lowercase,alt-require, andinline-style-disabled. - Enforce deterministic class and ID naming conventions (kebab-case vs BEM) using
id-class-value. - Author custom HTMLHint validation rules using the
HTMLHint.addRule()JavaScript API.
๐ The Mental Model & Story (Intuitive Foundation)
Think of the W3C Nu Validator (from Lesson 93.2) as a Building Code Inspector who checks whether the building will physically collapse under earthquake stress (spec conformance).
HTMLHint, on the other hand, is the Interior Design Quality Controller. It checks not only whether the building is legal, but whether the team adheres to agreed-upon styling conventions, maintainability standards, and organizational policies.
+-------------------------------------------------------------------------------+
| HTML QUALITY LAYERS |
+-------------------------------------------------------------------------------+
| 1. SPEC VALIDATION (W3C Nu Validator) -> "Is this legal according to WHATWG?"|
| 2. CODE CONVENTIONS (HTMLHint) -> "Does this follow our team rules?" |
| 3. ACCESSIBILITY TREE (axe-core) -> "Can humans with screen readers use it?"|
+-------------------------------------------------------------------------------+
For example, WHATWG permits uppercase tags (<DIV>) and single-quoted attributes (<a href='home'>). However, an engineering organization wants consistent lowercase naming, strictly double-quoted attributes, no messy inline style="..." attributes, and descriptive alt tags on every graphic. HTMLHint enforces this baseline at lightning speed.
Technical Deep Dive & Specifications
How HTMLHint Operates
HTMLHint is written entirely in JavaScript. Unlike heavy browser-engine validators, it uses a lightweight, high-performance HTML parser that scans tokens linearly. This makes it ideal for real-time editor feedback and fast pre-commit hooks.
The Complete .htmlhintrc Rule Matrix
{
"doctype-first": true,
"doctype-html5": true,
"tag-pair": true,
"tag-self-close": false,
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"attr-value-not-empty": false,
"attr-no-duplication": true,
"id-unique": true,
"src-not-empty": true,
"title-require": true,
"alt-require": true,
"spec-char-escape": true,
"id-class-value": "dash",
"style-disabled": false,
"inline-style-disabled": true,
"inline-script-disabled": true,
"space-tab-mixed-disabled": "space",
"id-class-ad-disabled": true,
"href-abs-or-rel": false,
"attr-unsafe-chars": true,
"head-script-disabled": false
}
Deep Dive into Essential Rules
| Rule Name | Allowed Values | What It Enforces & Why It Matters |
|---|---|---|
tag-pair |
true | false |
Verifies that every opened non-void element has a matching closing tag. Prevents runaway DOM nesting. |
id-unique |
true | false |
Guarantees that id values appear exactly once across the document. |
alt-require |
true | false |
Mandates that every <img> tag contains an alt attribute (even if empty alt="" for decorative images). |
attr-lowercase |
true | false |
Rejects uppercase attribute names like SRC= or DATA-ID=. |
attr-value-double-quotes |
true | false |
Enforces double quotes (attr="value") and flags single quotes or unquoted attributes. |
id-class-value |
"underline" | "dash" | "hump" | "bem" |
Enforces naming conventions on IDs and classes. "dash" enforces kebab-case; "bem" enforces block__elem--mod. |
inline-style-disabled |
true | false |
Disallows style="..." attributes, enforcing separation of presentation and strict Content Security Policies (CSP). |
inline-script-disabled |
true | false |
Disallows inline event listeners (onclick="...", onload="..."), preventing XSS vulnerabilities. |
Authoring Custom HTMLHint Rules
When your organization has custom markup constraints (for example: Every external link must include rel="noopener noreferrer"), you can write custom rules using HTMLHint.addRule().
// custom-rules/require-rel-noopener.mjs
import { HTMLHint } from 'htmlhint';
HTMLHint.addRule({
id: 'custom-external-rel-noopener',
description: 'External links with target="_blank" must include rel="noopener noreferrer".',
link: 'https://internal-docs.company.com/security/external-links',
init(parser, reporter) {
parser.addListener('tagstart', (event) => {
const tagName = event.tagName.toLowerCase();
if (tagName !== 'a') return;
const attrs = event.attrs;
const targetAttr = attrs.find(attr => attr.name.toLowerCase() === 'target');
const relAttr = attrs.find(attr => attr.name.toLowerCase() === 'rel');
if (targetAttr && targetAttr.value === '_blank') {
if (!relAttr || !relAttr.value.includes('noopener')) {
reporter.error(
'Anchor tag targeting _blank is missing rel="noopener noreferrer".',
event.line,
event.col,
this,
event.raw
);
}
}
});
}
});
๐ป Interactive Code Playground
Starter Code
Line-by-Line Code Breakdown
- Line 9:
<HEADER>uses uppercase tag characters, violatingtagname-lowercase: true. - Line 11:
onclick="logoutUser()"uses an inline JavaScript event handler, violatinginline-script-disabled: true. - Line 16:
style="margin-top: 20px;"uses an inline CSS declaration, violatinginline-style-disabled: true. - Line 18:
<img src="...">is missing analtattribute, violatingalt-require: true. - Line 21:
class="userProfileCard"usescamelCasewhen the policy enforcesid-class-value: "dash". - Line 23:
class='status-text'uses single quotes instead of double quotes, and the<p>tag is unclosed, violatingattr-value-double-quotesandtag-pair.
Expected Terminal Output from HTMLHint CLI
$ npx htmlhint "index.html" --config .htmlhintrc
index.html:
line 9, col 3: The tag name of [ <HEADER> ] must be in lowercase. [tagname-lowercase]
line 11, col 13: Inline script [ onclick="logoutUser()" ] cannot be used. [inline-script-disabled]
line 16, col 16: Inline style [ style="margin-top: 20px;" ] cannot be used. [inline-style-disabled]
line 18, col 7: An alt attribute must be present on <img> elements. [alt-require]
line 21, col 12: The value of attribute [ class="userProfileCard" ] must be in dash format. [id-class-value]
line 23, col 10: The value of attribute [ class='status-text' ] must be in double quotes. [attr-value-double-quotes]
line 23, col 7: Tag must be paired, no start tag: [ </section> ] on line 24. [tag-pair]
Scanned 1 file, found 7 errors in 1 file.๐๏ธ Hands-On Exercise
๐ฏ The Challenge: Build a 100% Clean Enterprise Registration Form
Instructions:
- Create a
.htmlhintrcconfiguration file specifying:tag-pair:trueattr-lowercase:trueattr-value-double-quotes:trueid-unique:truealt-require:trueid-class-value:"dash"inline-style-disabled:trueinline-script-disabled:true
- Refactor the dirty starter HTML snippet below to pass all configured HTMLHint rules cleanly.
๐ Starter Code Sandbox
โ ๏ธ Common Pitfalls
- Allowing Inline Event Handlers: Allowing
onclick="..."bypasses modern Content Security Policies (CSPscript-src 'self') and introduces Cross-Site Scripting (XSS) vectors. Always enableinline-script-disabled: true. - Ignoring
alt-requirefor Decorative Images: Some engineers addalt="image"or omit the attribute when an image is purely decorative. The rule requires the attribute to be present; for decorative assets, usealt=""explicitly. - Mixing Tabs and Spaces in Raw HTML: Inconsistent whitespace causes git merge conflicts. Use
"space-tab-mixed-disabled": "space"to enforce uniform 2-space indentation.
๐ก Pro Tips
- Run HTMLHint in Parallel with Prettier: Prettier formats the layout and whitespace, while HTMLHint verifies tag pairing, naming conventions, and security policies. Run Prettier first, then HTMLHint in your git hooks.
- Combine with VS Code HTMLHint Extension: Install the official
HTMLHintVS Code extension (htmlhint.vscode-htmlhint) so developers receive real-time red squiggles directly in their editor as they type.
๐ Key Takeaways
- HTMLHint is a fast, pure-JavaScript static analysis tool for linting static HTML documents and template files.
- Rules are configured via a project-root
.htmlhintrcJSON file. - Essential rules like
tag-pair,id-unique,attr-lowercase, andalt-requireprevent common markup regressions. - Enforcing
inline-style-disabledandinline-script-disabledstrengthens frontend application security and reinforces Content Security Policies. - The
HTMLHint.addRule()API allows engineering teams to construct custom, organization-specific validation policies. - --