HTML Formatter
Reindent HTML from the browser's own parsed DOM, keeping pre, textarea, script and style contents byte for byte.
HTML Formatter workspace
The document is reindented from the tree the browser parses, so <pre>, <textarea>,<script> and <style> keep their contents byte for byte.
Source Editor
Press Ctrl/Cmd + Enter to run.
Your draft is kept in this tab only (sessionStorage) and disappears when the tab closes. .
Result Console
Using HTML Formatter
Paste your markup into the editor, or press Load example for a sample fragment.
Choose an indent of 2 spaces, 4 spaces or Tab.
Press Format HTML to reparse the document and print the tree back out.
Compare the result with your source: any element that moved is a real nesting error.
The document is handed to DOMParser, the same parser the browser uses for a real page, and the output is generated by walking the resulting node tree. That is what lets it leave verbatim elements untouched, keep comments and attribute values intact, and handle angle brackets that appear inside scripts and attributes.
This page reindents markup. It doesn't validate it, minify it or rewrite your tags. It takes the document, hands it to the browser and prints the tree it gets back with consistent indentation.
Why it parses instead of pattern-matching
The input goes through DOMParser, the same HTML parser the browser uses for a real page, and the output comes from walking the node tree it produces. Most of how this page behaves follows from that choice. A parser knows the difference between a < that opens a tag and a < sitting inside a string, and a regular expression doesn't.
A regex-based formatter breaks in the same few ways every time:
<script>if (a < b && c > d)</script>was split at the comparison operators, which were read as tag boundaries. The script came out shredded.- Any attribute containing an angle bracket (
<div data-tpl="<%= name %>">, or an inline SVGpathwith a>in its data) broke the element around it. - Whitespace inside
<pre>was reindented, which changes what the browser actually renders.
What is preserved byte for byte
The contents of <pre>, <textarea>, <script> and <style> are emitted exactly as they arrived, with no reindenting or trimming. In the first two, whitespace is content, and the page looks different if you change it. The other two hold a different language entirely, and reindenting that isn't this tool's job.
Comments are kept. Attribute values are re-serialised with their contents intact. Inline elements such as <a>, <span>, <strong> and <code> stay on the line with the text around them. If you broke read the <a href="#">docs</a> first across three lines, the extra whitespace would show up in the rendered output as gaps.
Void elements are recognised, so <br>, <img>, <meta> and their siblings never get a spurious closing tag or an extra indent level.
The one setting
Indent is 2 spaces, 4 spaces or a tab, and that's the whole configuration. It's deliberate: a formatter with thirty options is a formatter whose output you can't predict.
What it will not tell you
The browser's parser is forgiving by specification, so it silently repairs a great deal. An unclosed <div> gets closed for you. A <p> inside a <p> gets split. A <td> outside a table gets relocated. You get a valid tree as a result, but it may not be the tree you wrote, and the differences are the interesting part. If the output has moved elements around, you've found a real bug in your markup and not in the formatter. Run the source through the W3C validator to see it named properly.
This page doesn't shrink anything either. Formatting adds bytes on purpose. Minification for production belongs in a build step, and for the assets around the markup there's CSS Minifier and JS Minifier.
A note on very large documents
Parsing and reserialising a whole 2 MB page works, but the tree walk and the syntax-highlighted view both grow linearly with the size of the document, and you'll feel it. It's built for formatting a component or a template fragment.
The markup you paste is parsed inside your own tab and never sent anywhere. The draft is kept in sessionStorage and disappears with the tab, or straight away if you use the "Clear it now" link.
Frequently asked
Does it fix broken markup?
Not on purpose. The browser's parser is forgiving by specification, so it closes an unclosed div, splits a paragraph nested inside a paragraph and relocates a stray table cell. The output is a valid tree, but if elements have moved you have found a genuine markup bug — the W3C validator will name it properly.
Will formatting change how my page renders?
It should not. Contents of pre and textarea are emitted unchanged because whitespace there is content, and inline elements such as anchors and spans stay on the line with the text around them so no extra gaps appear in the rendered output.
Does it reformat embedded CSS and JavaScript?
No. Script and style contents are copied out exactly as they arrived, because those are different languages and reindenting them is not this tool's job. Use the CSS and JavaScript tools for that work.
Why did the old regex-based version corrupt my code?
It could not tell an angle bracket in a tag from one inside a string. A comparison such as a < b inside a script was read as a tag boundary, an attribute containing a greater-than sign broke the element around it, and whitespace inside pre was reindented away.