HTML Formatter
Indent and wrap HTML with Prettier, without breaking the whitespace that inline elements actually depend on.
Your HTML
Formatted HTML
HTML is the hardest of the common languages to format correctly, and the reason is whitespace. In CSS or JavaScript you can insert a line break almost anywhere without changing meaning. In HTML you cannot: a newline between </span> and the word that follows it renders as a visible space, and removing the space between two inline-block elements changes the layout. A formatter that indents markup naively will silently alter how your page looks.
This page runs Prettier 3.9.6 with its HTML parser, which handles that problem by tracking the default CSS display type of every element. Block-level elements can be broken across lines freely; inline elements are treated as whitespace-sensitive and are only broken where the break cannot introduce or remove a rendered space. Everything runs in your browser, in a Web Worker, and nothing is uploaded.
How to use the html formatter
- 1
Paste a page, a fragment or a template
A full document, a partial, or a chunk copied out of DevTools all work. Note that the HTML path loads four Prettier plugins — the HTML parser plus PostCSS, Babel and estree — because embedded
<style>and<script>blocks are formatted with their own printers. They are fetched once and cached. - 2
Choose indentation
Two spaces, four spaces or tabs. Two is the usual choice for HTML, since deeply nested markup runs out of horizontal room quickly at four.
- 3
Copy, download or open in a new tab
Copy HTML puts plain text on the clipboard. Download HTML saves an
.htmlfile. Open in New Tab shows the formatted source on its own, which is handy for scanning a long document.
How whitespace sensitivity is handled
Prettier classifies each element by its default CSS display value and formats accordingly:
- Block elements such as
div,section,p,ulandtableget their children on their own indented lines. Surrounding whitespace is not rendered, so this is free. - Inline elements such as
span,a,em,strongandcodeare treated as part of the text flow. Prettier will wrap a long paragraph containing them, but only at points where a space already exists, so the rendered output is unchanged. - Pre-formatted content in
<pre>and<textarea>is copied through byte for byte. Every space and newline inside them is significant and none are touched.
This is why the output sometimes has a line ending in > immediately followed by text on the next line with no space, or a tag broken awkwardly before its closing bracket. That is not a bug — it is the printer refusing to add a space that would show up on screen. If you have ever formatted HTML in another tool and then wondered why gaps appeared between your inline links, you have met the alternative.
Attributes, embedded CSS and embedded JavaScript
When an element has enough attributes to exceed the 80-column print width, they are printed one per line with the closing bracket aligned to the opening tag. Short tags stay on one line. Attribute order is never changed — it has no effect on rendering, but reordering would produce noise in every diff.
The content of a <style> element is formatted as CSS, and the content of a <script> element is formatted as JavaScript, each using the same printer as the dedicated tool for that language. A <script type="application/json"> block is formatted as JSON. Scripts with a type Prettier does not recognise — an x-template block, for instance — are passed through untouched rather than guessed at.
Boolean attributes such as required and disabled keep their bare form. Void elements such as <img>, <br> and <input> are printed without a trailing slash, which is the HTML5 convention. Comments, the doctype, conditional comment syntax and character entities such as and — are all preserved exactly as written — entities are never decoded to the literal character, because and a plain space behave differently.
Template languages and what is not included
Prettier parses real HTML. Server-side template syntax embedded in it — Jinja, Twig, Blade, ERB, Handlebars, Liquid, Go templates — is not part of the HTML grammar. Some of it survives, because a {{ value }} expression inside a text node looks like text. Control-flow tags that wrap markup, such as a block that opens a <div> in one branch and closes it in another, will usually fail to parse, because the markup is unbalanced until the template engine runs. Format those files with a plugin in your own toolchain instead.
This tool does not minify, lint, sanitise or validate. It will not tell you that an <img> is missing its alt attribute, will not strip a <script> tag from untrusted markup, and will not check your document against the W3C validator. It does report a parse error with its position when the markup is broken beyond repair, for example when a tag is left unclosed in a way that cannot be recovered.
HTML Formatter FAQ
Why did the formatter leave some lines looking oddly broken?
Because a break in the wrong place would add or remove a rendered space. Inline elements are whitespace-sensitive, so Prettier only breaks where the change is invisible. The occasionally awkward line ending is the price of output that renders identically to your input.
Is my markup uploaded anywhere?
No. Prettier standalone runs as JavaScript in a Web Worker in your browser. Nothing is transmitted, which matters when the page you are formatting contains customer data, session tokens in a script block, or an unreleased marketing page.
Does it format the CSS and JavaScript inside my page?
Yes. <style> content is formatted as CSS and <script> content as JavaScript, which is why this page loads four Prettier plugins rather than one. A script with an unrecognised type attribute is left alone.
Will it fix unclosed tags?
It applies the standard HTML parsing rules, so genuinely optional closing tags — on <li> or <p>, for example — are handled the way a browser handles them. Malformed markup that cannot be parsed produces an error with the line and column instead of a guess.
Can it handle Vue, Angular or JSX files?
Not on this page. A Vue single-file component needs the Vue parser, Angular templates need the Angular parser, and JSX belongs to the JavaScript or TypeScript formatter. Plain HTML, including HTML containing Alpine or htmx attributes, is fine here.
