HTML Formatter & Beautifier: Clean Up HTML Code Online
Key Takeaways
- ▸HTML whitespace is fundamentally different from JSON or CSS — spaces between inline elements affect browser rendering, making "safe" reformatting impossible without CSS context.
- ▸Prettier (51,736 GitHub stars, ~55–82M weekly npm downloads) dominates HTML formatting; its
htmlWhitespaceSensitivityoption has three modes with documented edge cases in all of them. - ▸Google's HTML/CSS Style Guide mandates 2 spaces, never tabs — this is the industry consensus enforced by both Prettier defaults and major CI setups.
- ▸HTML minification removes 10–30% uncompressed, but after gzip compression the gain shrinks to 2–5% — often not worth the tooling complexity.
- ▸The Beautify VS Code extension (10.6M installs) has been unmaintained since May 2019 — switch to Prettier or js-beautify directly.
The Myth That Makes HTML Formatting Hard
Here is a common misconception: HTML formatting is trivial — just normalize indentation and call it done. JSON formatters work that way. CSS formatters work that way. But HTML is categorically different, and every engineer who has introduced Prettier into a legacy HTML codebase and shipped layout-breaking whitespace changes has learned this the hard way.
The root cause is architectural: HTML whitespace significance is determined by the CSS rendering engine, not the HTML parser. Per the WHATWG HTML specification, the parser must preserve all whitespace — the spec cannot say which spaces are visually meaningful because that depends on the computed CSS display property of each element, which is not known at parse time. A formatter that adds a newline between two <span> tags can insert a visible gap in rendered text. The same change between two <div> tags is invisible.
According to the Stack Overflow Developer Survey 2025 (49,000+ respondents across 177 countries), HTML/CSS is used by 62% of developers — ranked third after JavaScript (66%) and Python (62%). That is a massive surface area for formatting inconsistency. Understanding how HTML formatters actually work — and where they fail — is practical knowledge, not pedantry.
How HTML Formatters Work (And Why They Struggle)
A JSON formatter's job is simple: tokenize the input, parse it to an AST, then serialize with consistent indentation. Because JSON whitespace is completely insignificant between tokens, the formatter can add or remove any whitespace without changing semantics. HTML formatters cannot make the same guarantee.
The core challenge is described clearly by developer Ben Wainwright in his analysis of HTML whitespace behavior: "the HTML parser must retain all spaces because it's actually the CSS layer which decides whether or not those spaces are significant." This means a correct HTML formatter would need to:
- Parse the HTML into a DOM tree
- Determine the computed CSS
displayvalue for every element (which requires loading the stylesheet) - Apply whitespace-safe reformatting only where the display type guarantees whitespace is insignificant
- Preserve all whitespace around inline elements to avoid changing rendered output
No formatter does this correctly for all cases. Instead, tools maintain lookup tables of known HTML elements and their default CSS display values per the HTML5 spec. Custom web components (<my-header>), Angular components (<app-navbar>), and Vue components (<ProductCard>) are unknown, so formatters conservatively treat them as inline — which produces over-cautious formatting even when the component renders as a block.
BytePane's HTML Formatter processes your markup client-side, applying consistent indentation using known HTML5 element semantics.
HTML Formatter Tools: Feature & Popularity Comparison
Five tools dominate the HTML formatting space, with dramatically different philosophies and maintenance status:
| Tool | GitHub Stars | Weekly Downloads | Type | Last Release |
|---|---|---|---|---|
| Prettier | 51,736 | ~55–82M | Formatter | v3.7.0 (Nov 2025) |
| js-beautify | ~9,000 | Several million | Formatter | Active |
| HTMLHint | 3,300 | ~87K–121K | Linter only | v1.9.2 (Mar 2026) |
| Beautify (VS Code ext) | — | 10.6M installs | Formatter (js-beautify) | May 2019 ⚠ |
| HTML Tidy (tidy-html5) | 2,900 | CLI/C library | Formatter + repair | v5.8.0 (Jul 2021) ⚠ |
The most important number in this table: the Beautify VS Code extension has 10.6 million installs but has not been updated since May 2019. It wraps js-beautify, which is itself maintained — but the extension no longer supports modern VS Code APIs, does not handle modern HTML5 features, and has no active maintainer. If you have this extension installed, switch to Prettier's official VS Code extension (esbenp.prettier-vscode) or use js-beautify directly via the CLI.
Biome, the emerging Rust-based formatter claiming 10–25x speed improvements over Prettier for JavaScript and TypeScript, does not yet support HTML as of early 2026 — it remains on the roadmap.
Prettier's htmlWhitespaceSensitivity: All Three Modes Explained
Prettier's htmlWhitespaceSensitivity option is the single most important configuration decision for HTML formatting. It controls how Prettier decides when whitespace is semantically significant. Set this wrong and you will ship invisible layout changes.
| Mode | Behavior | Safe For | Risk |
|---|---|---|---|
| css | Respects CSS display defaults — block elements treated as insensitive, inline as sensitive | Standard HTML5 documents | Custom elements default to inline |
| strict | All whitespace around all tags treated as significant — most conservative | Apps with heavy custom CSS overrides | Produces verbose, barely-reformatted output |
| ignore | All whitespace treated as insignificant — maximum reformatting | Email templates, server-rendered HTML | Can alter rendered layout for inline elements |
The css default is the right starting point for most projects, but be aware of its documented limitations. As of early 2026, Prettier GitHub Issue #15724 (open) documents that Angular templates with control flow syntax (@if, @for) do not respect the whitespace sensitivity setting and add incorrect whitespace around text bindings. Issue #16436 notes that --html-whitespace-sensitivity has no effect on JSX at all — JSX formatting follows its own rules regardless of this option.
The practical recommendation: use css mode, add <!-- prettier-ignore --> comments on any markup where whitespace is visually critical, and always review HTML-only diffs carefully in code review.
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"htmlWhitespaceSensitivity": "css",
"singleAttributePerLine": false,
"bracketSameLine": false
}The 14 Void Elements: What Every HTML Formatter Must Know
The WHATWG HTML Living Standard defines exactly 14 void elements — elements that cannot have child content and must not have closing tags:
area base br col embed hr img input link meta param source track wbr
This matters for HTML formatters because these elements have distinct rules:
- No closing tag:
</br>or</img>are syntax errors. A good formatter strips them. - Trailing slash is legal but ignored:
<br />and<br>are functionally identical per the spec. The slash is XML legacy from XHTML and has no semantic effect in HTML5 documents. - Self-closing syntax on non-void elements breaks the DOM: Writing
<div />or<script />is a parsing error. HTML parsers treat the slash as part of an attribute name, not as a closing indicator. Everything after<div />becomes a child node of that div rather than a sibling.
The self-closing non-void pattern is the most common HTML syntax error introduced by developers coming from React/JSX where <Component /> is idiomatic. HTMLHint catches this with its tag-self-close rule. Prettier strips invalid self-closing slashes from non-void elements when reformatting.
HTML Indentation Standards: 2 Spaces Has Won
The indentation debate is mostly settled for HTML. Here is what the authoritative style guides actually say:
| Style Guide | Standard | Tabs? | Note |
|---|---|---|---|
| Google HTML/CSS Style Guide | 2 spaces | Never | "Do not use tabs or mix tabs and spaces" |
| Airbnb Style Guide | 2 spaces | Never | Consistent with JS guide |
| Prettier default | 2 spaces | Configurable | Via tabWidth / useTabs |
| Bootstrap documentation | 2 or 4 spaces | Discouraged | Either acceptable |
| W3C style examples | 4 spaces | Sometimes | Older, less prescriptive |
2 spaces is the practical winner. The Google HTML/CSS Style Guide — which is the most widely cited web coding standard in the industry — explicitly forbids tabs and mandates 2-space indentation. Prettier defaults to 2 spaces. For a deeply nested HTML document (8–10 levels of nesting), 2-space indentation keeps lines within a 100-character print width; 4-space indentation pushes deeply-nested content past 80 characters with only 4–5 nesting levels.
Tabs are avoided specifically because tab width rendering varies by editor configuration: a developer using VS Code with 4-wide tabs and another using a terminal with 8-wide tabs will see completely different visual indentation from the same source file. For HTML — where visual structure communicates nesting hierarchy — this is a meaningful readability problem.
HTMLHint: Static Analysis for HTML (Linting, Not Just Formatting)
HTMLHint (3,300 GitHub stars, ~87K–121K weekly npm downloads, v1.9.2 released March 2026) is the standard static analysis tool for HTML. It does not reformat code — it detects violations. This distinction matters: a formatter fixes whitespace; HTMLHint catches semantic and structural problems that formatting cannot address.
HTMLHint provides 44 rules across 6 categories. The most practically useful:
| Rule | Category | What It Catches |
|---|---|---|
| doctype-first | Doctype | Missing <!DOCTYPE html> declaration |
| attr-value-double-quotes | Attributes | Attribute values using single quotes instead of double |
| tag-self-close | Tags | Self-closing syntax on non-void elements |
| tagname-lowercase | Tags | Uppercase tag names (<DIV> instead of <div>) |
| alt-require | Accessibility | Missing alt attributes on <img> |
| inline-style-disabled | Inline | Inline style attributes on elements |
{
"doctype-first": true,
"attr-value-double-quotes": true,
"tag-self-close": true,
"tagname-lowercase": true,
"alt-require": true,
"id-unique": true,
"inline-style-disabled": false,
"spec-char-escape": true
}The recommended workflow pairs both tools: Prettier handles formatting on save, HTMLHint runs in CI to catch structural violations that formatting cannot fix. Use lint-staged to run both on staged files only so your commit pipeline stays fast.
Automating HTML Formatting in CI/CD
Format-on-save in VS Code is a local convention, not an enforcement mechanism. Any developer who does not have the right extension installed, or who edits HTML files outside the IDE, will commit unformatted code. CI enforcement is the only reliable gate.
name: Lint & Format Check
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
# Check all HTML files are formatted
- name: Prettier format check
run: npx prettier --check "**/*.html" "**/*.tsx" "**/*.jsx"
# Lint HTML for structural issues
- name: HTMLHint
run: npx htmlhint "src/**/*.html" "public/**/*.html"For pre-commit hooks, the standard stack is husky + lint-staged:
{
"lint-staged": {
"*.html": [
"prettier --write",
"htmlhint"
],
"*.{tsx,jsx}": [
"prettier --write"
]
}
}One critical caveat: pre-commit hooks can be bypassed with git commit --no-verify. This is not a hypothetical — developers under deadline pressure use it. Server-side CI enforcement via GitHub Actions cannot be bypassed and should be the authoritative gate for format compliance.
HTML Minification vs Formatting: The Performance Trade-off
Developers often conflate HTML formatting (for readability) with HTML minification (for performance). They are opposite operations. Minification removes whitespace, comments, and optional closing tags to reduce file size. Formatting adds whitespace to improve readability. You do one in development and the other in production.
The question is: how much does HTML minification actually help? Perfection Kills benchmarked major websites and found the following uncompressed savings:
| Site | Original | Minified | Uncompressed Saving |
|---|---|---|---|
| Amazon.com | 217 KB | 206.6 KB | 4.8% |
| LinkedIn.com | 128.8 KB | 89.4 KB | 30.6% |
| Ajaxian.com | 177.6 KB | 157.3 KB | 11.4% |
| Digg.com | 82 KB | 74.9 KB | 8.5% |
The catch: gzip compression dramatically reduces these gains. Gzip works by finding repeated patterns — whitespace is highly repetitive, so it compresses extremely well. LinkedIn's 30.6% uncompressed saving shrinks to approximately 2–3% after gzip. For sites already serving gzip-compressed HTML (which should be all of them in 2026), HTML minification has negligible performance impact.
The real performance wins come from elsewhere: image optimization, JavaScript bundle splitting, Core Web Vitals improvements, and proper caching headers. Our 2026 Web Performance Checklist covers the full stack of high-ROI optimizations.
Setting Up HTML Formatting in VS Code
The recommended VS Code setup for HTML formatting combines Prettier for auto-formatting with HTMLHint for linting:
- Install Prettier extension:
esbenp.prettier-vscode— the official extension, actively maintained.⚠ Do NOT use HookyQR.beautify (10.6M installs but unmaintained since 2019) - Install HTMLHint extension:
htmlhint.vscode-htmlhint - Configure settings.json:
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.htmlWhitespaceSensitivity": "css",
"prettier.printWidth": 100,
"prettier.tabWidth": 2
}For React/Next.js projects, HTML-in-JSX formatting is handled by the JSX formatter, not the HTML formatter. The htmlWhitespaceSensitivity option does not apply to .tsx files — JSX whitespace rules are different and Prettier handles them via its React plugin. Our JavaScript/TypeScript Beautifier handles JSX formatting directly in the browser.
For templating languages (Handlebars, Nunjucks, Liquid), Prettier has official plugins: prettier-plugin-jinja-template for Liquid/Jinja, and prettier-plugin-go-template for Go templates. Configure them as plugins in your .prettierrc.
HTML Formatting Reference: Before and After
These are the most common formatting transformations an HTML beautifier performs. Understanding the before/after helps you catch regressions and configure your formatter correctly.
Inconsistent Indentation
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav><nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>Mixed Attribute Quotes
<img src='logo.png' alt="Logo" class='header-logo' width=120>
<img src="logo.png" alt="Logo" class="header-logo" width="120" />
Whitespace Sensitivity (⚠ Inline elements)
<!-- Renders: "Hello World" (space preserved) --> <p>Hello <span>World</span></p> <!-- After aggressive formatting --> <!-- May render: "HelloWorld" (space lost) --> <p> Hello <span>World</span> </p>
<!-- Whitespace between divs is
always safe to modify -->
<div>
<div>Section 1</div>
<div>Section 2</div>
</div>Frequently Asked Questions
What is the best HTML formatter?
Prettier (51,736 GitHub stars, ~55–82M weekly npm downloads) is the dominant choice for projects that use JavaScript and CSS alongside HTML, because it handles all three consistently with a single config. For HTML-only or legacy projects, js-beautify offers more configuration options. The Beautify VS Code extension (10.6M installs) is widely installed but unmaintained since May 2019 — don't use it for new projects.
Does HTML formatting affect browser rendering?
It can. Whitespace between inline elements (like <span> tags) is semantically significant in HTML and can affect rendered layout. A newline between two inline elements can insert or remove a visible space in the output. Prettier's htmlWhitespaceSensitivity css mode minimizes this risk for standard HTML5 elements, but custom web components are treated as inline by default regardless of their actual CSS display value.
Should I use 2 spaces or 4 spaces for HTML indentation?
2 spaces. Google's HTML/CSS Style Guide explicitly mandates 2 spaces (never tabs), and this is the industry-dominant standard enforced by Prettier's defaults and most team configurations. 4-space indentation becomes unwieldy for HTML with deep nesting — typical templates hit 8–10 levels, and 4 spaces per level pushes content well past 80-character line limits.
What are void elements in HTML?
Void elements are the 14 HTML elements that cannot have children: area, base, br, col, embed, hr, img, input, link, meta, param, source, track, wbr. They must not have closing tags. The HTML5 spec permits trailing slashes like <br /> for XML compatibility, but <div /> on a non-void element is a parse error that causes everything after it to be nested inside, breaking the DOM structure.
How do I format HTML in VS Code?
Install esbenp.prettier-vscode (the official Prettier extension), set "editor.defaultFormatter" to "esbenp.prettier-vscode" in settings.json, and enable "editor.formatOnSave". Configure htmlWhitespaceSensitivity in .prettierrc. For linting (structural issues, not just whitespace), also install the HTMLHint extension (htmlhint.vscode-htmlhint) which runs 44 rules and highlights violations inline.
Does HTML minification actually improve performance?
In practice, barely. Uncompressed, whitespace removal reduces HTML file sizes by 10–30% (LinkedIn's homepage saw 30.6% per Perfection Kills benchmarks). But gzip compression already collapses repetitive whitespace effectively, so the net gain after gzip is typically 2–5%. The performance ROI of HTML minification is marginal compared to image optimization, JavaScript bundle reduction, or fixing Core Web Vitals.
Format HTML Instantly — No Setup Required
Paste your HTML and get clean, consistently-indented code back in seconds. Runs entirely in your browser — no data sent to any server.
Open HTML Formatter →