HTML Formatter
Pretty-print messy or minified HTML into clean, editor-consistent Prettier output — entirely on this device.
Whitespace between inline elements is content. CSS follows each element's default display, Strict keeps every space, and Ignore is free to add or remove space — Ignore can change how the page renders.
This tool formats — it does not validate. Prettier's parser refuses mismatched end tags and unknown entities instead of guessing a repair.
Bodies of <script> and <style> are re-indented, not reformatted. Format those here: JavaScript Beautifier · CSS Formatter
Press ? for shortcuts
Do it offline:$ npx prettier --parser html page.html
How to use it
- Paste markup or drop a .html file — the file is read in place, and a document under 64 KB re-formats as you type.
- Set the print width and indent width, pick spaces or tabs, and choose a whitespace mode: CSS, Strict or Ignore.
- If the parser refuses the document, the strip below the panes carries its exact words, the line and column, and a caret frame — your input is left as pasted.
- Take the result with Copy, save it with Download, or share a permalink that reopens the same markup and the same settings.
Paste a wall of minified markup and read back indented HTML, printed by Prettier's own HTML parser running in a Web Worker on this device — nothing is uploaded. Print width, indent width and whitespace mode are yours to set. Because the space around an inline element is rendered text, not decoration, each option here states which way it can move what a browser draws.
How it works
One plugin is loaded: Prettier's HTML printer, driven by its standalone build inside a Web Worker so a large document reprints without stalling the tab. Underneath sits angular-html-parser, the same parser the prettier --parser html command line reaches for, which is why the bytes below and the bytes your repository's format check produces line up.
HTML is not free-form text. A space between a closing tag and the next opening tag is a space the browser paints, so indenting wherever it pleases would let a formatter rewrite the visible page. The printer settles this per element using its default CSS display: around inline elements such as em, a and span the surrounding whitespace is treated as significant and left alone, while block elements are free to take their own line. That is the CSS mode, and it is the reason a sentence with markup inside it comes back on one line while its container is indented.
Beyond layout the parser normalizes a short, fixed list of spellings: tag names and the attribute names HTML defines come back lower-case, unquoted attribute values gain double quotes, void elements print self-closing, optional end tags are written out, and the doctype keyword is lower-cased. An attribute the standard does not define keeps the capitalisation you gave it, and attribute values, text, comments, entity references and element order are never edited — a conditional comment for old Internet Explorer and a textarea's exact spacing both come back byte for byte.
Where a browser would guess, this parser stops. A closing tag with no matching opener and an entity name outside the HTML entity table are refusals, each reported with a position and a caret rather than a silent repair, because repairing markup means changing the document instead of printing it.
Examples
<div class="card"><h2>Title</h2><p>Hello <em>world</em>, welcome back.</p></div><div class="card">
<h2>Title</h2>
<p>Hello <em>world</em>, welcome back.</p>
</div>
The two block children each take a line at two-space indentation while the sentence wrapping em stays whole. Delete the whitespace sitting between tags in both texts and they are the same characters in the same order.
<UL CLASS=nav><LI>Home<LI>Docs</UL><HR><ul class="nav">
<li>Home</li>
<li>Docs</li>
</ul>
<hr />
Four normalizations at once: UL and LI come back lower-case, the bare nav value is quoted, the list items that HTML lets you leave open are closed explicitly, and HR is printed self-closing.
<p>Total:<b>10</b>USD</p><p>
Total:
<b>10</b>
USD
</p>
Under the default CSS mode this paragraph comes back exactly as pasted. Ignore is allowed to break inside it, and each of those new line breaks is whitespace a browser renders: the page changes from reading Total:10USD to reading Total: 10 USD. That is the trade the mode carries, so it is shown rather than buried.
<img src="hero.png" alt="Ithomia" width="640"><img
src="hero.png"
alt="Ithomia"
width="640"
/>
Left alone this tag fits the print width and comes back on one line. Turning on One attribute per line in the options rail gives each attribute its own row and moves the closing bracket down to a line of its own, so a later diff shows only the attribute that changed. The element, its attributes and their order are identical in both spellings.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Choosing between CSS, Strict and Ignore
CSS is the safe default: significant whitespace is decided per element from its default display. Strict treats every space as significant everywhere — output stays faithful, at the cost of the tag-hugging spelling where an opening tag ends with its angle bracket on the next line. Ignore reads most cleanly and is the one mode that may add or drop rendered space, so keep it for markup whose layout you control.
pre and textarea keep their bytes
Content inside pre and textarea is never re-indented. A newline may appear right after an opening pre tag, which is safe: the HTML parsing spec discards a single leading newline inside pre, so the rendered block is unchanged. Everything after that first newline is yours, spaces and all.
Formatting is not validating
Nothing here grades your markup. Duplicate attributes, unknown elements, a bare ampersand in text and a stray less-than sign all print without comment, because only a parse failure stops a run. Checking a document against the standard is a different job, and the entity table has its own reference tool planned.
Embedded script and style are re-indented, not reprinted
Only the HTML plugin is loaded, which keeps roughly 190 KB of JavaScript and CSS printers off the page. The body of a script or style element is therefore moved to the right indentation and otherwise left alone; run those bodies through the JavaScript Beautifier or the CSS Formatter. The command line below bundles those printers, so on a document carrying embedded code it also reprints the bodies — add --embedded-language-formatting=off there to reproduce this page byte for byte.
Invisible bytes are reported, not swallowed
A leading byte-order mark is removed and announced with the note “Leading byte-order mark removed”; Prettier on its own would pass it through. Any unpaired UTF-16 surrogate becomes the U+FFFD replacement character with a warning, so the markup handed back is always well-formed text.
Where the ceiling sits
Every run is handed to a background worker, whatever the size, so the tab keeps responding while a document is being printed. Under 64 KB the markup reprints as you type; above that a short pause is added before each run, and past 2 MB the tool stops reprinting on every keystroke and waits for the run shortcut. The ceiling is 4 MB: above it the tool declines, names the limit and hands over the command line below.
Common errors
Unexpected closing tag "div". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags at line 1, column 12.- A closing tag arrived where the parser had a different element open — here a span was still open when div was closed. The same words appear when a fragment is pasted without its opening tag, for instance a lone closing body tag at the start of the document.
Unknown entity "nope" - use the "&#<decimal>;" or "&#x<hex>;" syntax at line 1, column 7.- An ampersand-name-semicolon sequence that is not in the HTML entity table cannot be printed as either text or a character reference, so the run stops at the ampersand. Write the numeric form the message quotes, or escape the ampersand itself as &.
Opening tag "div" not terminated at line 1, column 1.- An opening tag was never closed by an angle bracket — usually a truncated paste or a quote swallowing the rest of the tag. The column points at the start of that tag, not at the end of the file, so the caret frame lands where the trouble began.
FAQ
Can formatting change how my page renders?
In the default CSS mode and in Strict, no: whitespace that the browser would paint is preserved. Ignore is the exception and says so in the options rail — it may add or remove rendered space around inline elements. The third example on this page shows exactly that happening.
Why does the output say <br /> when I wrote <br>?
The printer writes void elements in the self-closing spelling. Both forms parse to the same element in HTML, so nothing about the document changes; it is a spelling convention Prettier applies everywhere, alongside lower-casing tag names and quoting bare attribute values.
Why did my DOCTYPE come back in lower case?
The doctype is kept, with its keyword lower-cased: a document starting with an upper-case DOCTYPE declaration is printed as <!doctype html>. HTML treats the keyword case-insensitively, so the document type is unchanged — only the letters differ.
Why refuse a broken document instead of fixing it?
Repairing markup means deciding what the author meant, and two repairs of the same page can render differently. A mismatched closing tag or an unrecognised entity therefore stops the run with the parser's own words plus a line, a column and a caret, and your input is returned untouched for you to fix.
Are my script and style blocks reformatted too?
No — their bodies are re-indented to sit at the right depth, and the code inside them is left exactly as written. Loading the JavaScript and CSS printers as well would roughly triple what this page downloads, so those two jobs stay on their own tools.
Will this match Prettier in my editor and in CI?
For markup without embedded code it should, byte for byte, when the versions and options agree. This page runs the published defaults — width 80, two-space indent, CSS whitespace mode — so if two results differ, compare Prettier versions before anything else.
How large a document can it take, and is any of it uploaded?
Nothing is uploaded: the parser runs in this browser tab, and dropped files are read locally. The limit is 4 MB of text; past that the tool refuses rather than freeze, and points you at the command line instead.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Format the markup, or re-run it.
- ⌘/Ctrl + S
- Download the formatted markup.
- ⌘/Ctrl + C
- Copy the output pane, nothing selected.
- ⌘/Ctrl + Shift + C
- Copy the output pane regardless.
- t
- Switch the theme.
- ? or ⌘/Ctrl + /
- Open this page's shortcut list.
- Esc
- Dismiss the front dialog, input intact.