๐Ÿ› ๏ธ Chapter 93: HTML Tooling, Linting & Quality Assurance

HTMLHint Configuration & Rules

Static analysis for static and template markup using HTMLHint, configuring `.htmlhintrc` rule matrices, enforcing naming conventions, and authoring custom lint rules.

LEARNING OBJECTIVES โŒต
  • Understand the architecture of HTMLHint as a lightweight, fast AST-free regex/tokenizer static analyzer.
  • Construct a production-grade .htmlhintrc configuration file enforcing enterprise style guides.
  • Configure critical rules: tag-pair, id-unique, attr-lowercase, alt-require, and inline-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.
๐ŸŽฌ INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
๐ŸŒ
1. Input
Directives & Tags
โš™๏ธ
2. Parse
Tokenizer & AST
๐ŸŒณ
3. Layout
Box Model & Flow
๐ŸŽจ
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

๐Ÿ“– 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, violating tagname-lowercase: true.
  • Line 11: onclick="logoutUser()" uses an inline JavaScript event handler, violating inline-script-disabled: true.
  • Line 16: style="margin-top: 20px;" uses an inline CSS declaration, violating inline-style-disabled: true.
  • Line 18: <img src="..."> is missing an alt attribute, violating alt-require: true.
  • Line 21: class="userProfileCard" uses camelCase when the policy enforces id-class-value: "dash".
  • Line 23: class='status-text' uses single quotes instead of double quotes, and the <p> tag is unclosed, violating attr-value-double-quotes and tag-pair.

Expected Terminal Output from HTMLHint CLI


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45ยฐC
INSPECTING DOM: VALID
TAGS: SCANNING...
$ 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:

  1. Create a .htmlhintrc configuration file specifying:
    • tag-pair: true
    • attr-lowercase: true
    • attr-value-double-quotes: true
    • id-unique: true
    • alt-require: true
    • id-class-value: "dash"
    • inline-style-disabled: true
    • inline-script-disabled: true
  2. Refactor the dirty starter HTML snippet below to pass all configured HTMLHint rules cleanly.

๐Ÿ Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45ยฐC
INSPECTING DOM: VALID
TAGS: SCANNING...

โš ๏ธ Common Pitfalls

  1. Allowing Inline Event Handlers: Allowing onclick="..." bypasses modern Content Security Policies (CSP script-src 'self') and introduces Cross-Site Scripting (XSS) vectors. Always enable inline-script-disabled: true.
  2. Ignoring alt-require for Decorative Images: Some engineers add alt="image" or omit the attribute when an image is purely decorative. The rule requires the attribute to be present; for decorative assets, use alt="" explicitly.
  3. 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

  1. 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.
  2. Combine with VS Code HTMLHint Extension: Install the official HTMLHint VS 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 .htmlhintrc JSON file.
  • Essential rules like tag-pair, id-unique, attr-lowercase, and alt-require prevent common markup regressions.
  • Enforcing inline-style-disabled and inline-script-disabled strengthens frontend application security and reinforces Content Security Policies.
  • The HTMLHint.addRule() API allows engineering teams to construct custom, organization-specific validation policies.
  • --
โญ LEARN: HTML ๐ŸŒŸ โš”๏ธ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

Which .htmlhintrc rule ensures that no two elements in the same HTML file share the identical identifier?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

What is the primary security benefit of enforcing inline-script-disabled: true in HTMLHint?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

When using "id-class-value": "dash" in .htmlhintrc, which of the following class names will trigger a lint violation?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP