What the formatter handles
HTML ends up unreadable in many ways: a minified production page you need to debug, the output of a WYSIWYG editor, an email template built from nested tables, or a component snippet copied from browser DevTools. This page runs Prettier, the formatter most front-end teams already use, so the result matches what a Prettier-configured editor produces. <style> blocks are formatted as CSS and <script> blocks as JavaScript in the same pass.
Prettier follows the HTML parsing rules browsers use, including implied end tags. <li>One<li>Two is valid HTML and comes out with explicit </li> tags. Markup that is genuinely broken, such as a closing tag for an element that is not open, is reported with its line and column.
A Preview tab renders the input in a sandboxed frame after sanitising it, so you can compare structure and appearance side by side. Scripts in the pasted HTML are not executed.
Formatting and minifying
Paste markup or drop an .html file, then press Ctrl/Cmd+Enter to beautify. Ctrl/Cmd+Shift+M minifies with html-minifier-terser: whitespace is collapsed conservatively (one space is kept where a space would render), comments are removed, boolean attributes are shortened (disabled="disabled" becomes disabled), and inline CSS and JavaScript are minified too. Entities such as & are not decoded, so the minified page shows the same text. Ctrl/Cmd+Shift+C copies the output; Ctrl/Cmd+K opens the command palette.
Templates often include tracking IDs, internal URLs or customer data, so it helps that the formatter runs entirely client-side.
Options
Whitespace sensitivity is the setting that matters most, because in HTML the space between two inline elements is visible on the page.
- Respect CSS display (default) treats whitespace around inline elements such as
<a>,<span>and<strong>as significant and around block elements such as<div>and<p>as insignificant. To avoid adding a visible space, Prettier sometimes moves a>to the start of the next line, which looks odd but renders identically. - Strict (never change rendering) treats all whitespace as significant. Use it for markup where every element may be styled inline, such as email templates.
- Ignore treats whitespace as insignificant everywhere. The output is the cleanest, but it can add or remove a space between inline elements, for example between an icon and its label.
One attribute per line puts every attribute of a multi-attribute element on its own line, the style many Vue and Angular teams prefer for long <input> and <button> tags.
Keep > on the last attribute line places the closing > of a wrapped start tag at the end of the last attribute instead of on its own line.
Indent and line width apply as usual; line width decides when a start tag’s attributes wrap.
Limits worth knowing
- Template syntax inside HTML (Jinja
{% %}, Handlebars{{#each}}, PHP<?php ?>) is not understood by the HTML parser. Use the Handlebars formatter or PHP formatter for those files, and the Vue or Angular formatter for framework templates. - Formatting is not validation against the HTML specification. Unknown elements and attributes are accepted, as browsers accept them; only structural errors stop formatting.
- Converting HTML for other uses is a separate step: HTML to Markdown for docs and HTML to JSX for React components.
Examples
Minified landing page
The page is indented by element nesting, and the embedded style and script blocks are formatted as CSS and JavaScript.
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Spring Sale</title><style>.hero{padding:4rem 1rem;text-align:center}.hero a{background:#e11d48;color:#fff;padding:.75rem 1.5rem;border-radius:6px}</style></head><body><section class="hero"><h1>Spring Sale: 30% off keyboards</h1><p>Ends <time datetime="2026-04-30">April 30</time>. Free shipping over $50.</p><a href="/sale?utm_source=email&utm_campaign=spring">Shop the sale</a></section><script>document.querySelector('.hero a').addEventListener('click',()=>{window.dataLayer?.push({event:'sale_click'})})</script></body></html><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Spring Sale</title>
<style>
.hero {
padding: 4rem 1rem;
text-align: center;
}
.hero a {
background: #e11d48;
color: #fff;
padding: 0.75rem 1.5rem;
border-radius: 6px;
}
</style>
</head>
<body>
<section class="hero">
<h1>Spring Sale: 30% off keyboards</h1>
<p>
Ends <time datetime="2026-04-30">April 30</time>. Free shipping over
$50.
</p>
<a href="/sale?utm_source=email&utm_campaign=spring">Shop the sale</a>
</section>
<script>
document.querySelector(".hero a").addEventListener("click", () => {
window.dataLayer?.push({ event: "sale_click" });
});
</script>
</body>
</html>
Sign-up form with one attribute per line
Every multi-attribute element lists its attributes vertically, with the closing > kept on the last attribute line.
<form action="/api/signup" method="post" class="signup" novalidate><label for="email">Work email</label><input id="email" name="email" type="email" autocomplete="email" required placeholder="you@company.com"><label for="plan">Plan</label><select id="plan" name="plan"><option value="starter">Starter</option><option value="team" selected>Team</option></select><button type="submit" class="btn btn-primary" data-track="signup-submit">Create account</button></form><form
action="/api/signup"
method="post"
class="signup"
novalidate>
<label for="email">Work email</label
><input
id="email"
name="email"
type="email"
autocomplete="email"
required
placeholder="you@company.com" /><label for="plan">Plan</label
><select
id="plan"
name="plan">
<option value="starter">Starter</option>
<option
value="team"
selected>
Team
</option></select
><button
type="submit"
class="btn btn-primary"
data-track="signup-submit">
Create account
</button>
</form>
Email template formatted with strict whitespace
Strict mode never adds or removes a space between the inline strong and link elements, which email clients would render.
<table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr><td style="padding:24px;font-family:Arial,sans-serif"><p style="margin:0 0 12px">Hi Aisha,</p><p style="margin:0">Your order <strong>#1001</strong> has shipped. <a href="https://shop.example.com/orders/1001" style="color:#2563eb">Track it</a> or <a href="https://shop.example.com/help">contact us</a>.</p></td></tr></table><table role="presentation" width="100%" cellpadding="0" cellspacing="0"
><tr
><td style="padding: 24px; font-family: Arial, sans-serif"
><p style="margin: 0 0 12px">Hi Aisha,</p
><p style="margin: 0"
>Your order <strong>#1001</strong> has shipped.
<a href="https://shop.example.com/orders/1001" style="color: #2563eb"
>Track it</a
>
or <a href="https://shop.example.com/help">contact us</a>.</p
></td
></tr
></table
>
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Unexpected closing tag "div". It may happen when the tag has already been closed by another tag.Explained | There is one more </div> than opening <div> tags, or an element was closed in the wrong order, such as <p><b>text</p>. | Remove the extra closing tag, or close inner elements before outer ones (</b></p>). The reported line is where the unmatched tag sits. |
Unexpected character "EOF" | The input ended inside a tag or attribute value, usually because an attribute quote was never closed, as in class="card>. | Close the quote or the tag; editors that highlight attribute values make the unclosed one obvious. |
Output has > at the start of lines | Whitespace sensitivity is set to Respect CSS display, and adding a line break between two inline elements would add a visible space. | Leave it if exact rendering matters, or switch Whitespace sensitivity to Ignore when the spacing between inline elements does not matter. |
Frequently asked questions
Will beautifying change how my page looks?
Not with the default or Strict whitespace setting, which only adds line breaks where browsers ignore them. The Ignore setting can change spacing between inline elements.
How do I format HTML in VS Code?
Right-click and choose Format Document, or press Shift+Alt+F (Shift+Option+F on macOS). VS Code’s built-in formatter is js-beautify; install the Prettier extension to get the same output as this page.
Is it safe to paste HTML with scripts?
Yes. Formatting treats scripts as text, and the Preview renders a sanitised copy in a sandboxed frame, so nothing in the pasted page runs. The markup is also never uploaded.
Does the minifier remove comments?
Yes, all HTML comments are removed. Conditional comments for old Outlook versions are comments too, so keep the beautified version for email templates that rely on them.
Can it fix invalid HTML?
It normalises valid shortcuts like implied </li> and </p> tags. Genuinely broken structure, such as a stray closing tag, is reported with its position rather than guessed at.