What this tool does
The tool reads your markup the way browsers do. It follows the HTML tokenizer for tags, quoted, unquoted and valueless attributes, comments, the DOCTYPE and raw text, and a simplified version of the browser's tree builder for void elements such as <br> and <img>, optional end tags such as </li> and </p>, elements that end others (a <div> closes an open <p>), tables, <select>, <template>, and SVG or MathML, where <path /> really is self-closing. Formatting only changes whitespace: no tag is added or removed, and attributes keep their order, quotes and case. Because whitespace is rendered in some places and not in others, each gap is judged by the default CSS display of the elements around it. Next to a block element such as <div>, <p>, <li> or <td> whitespace is not shown, so blocks go on their own lines. Between inline content (text, <a>, <span>, <strong>, <img>, <button>) a space is shown, so a run of spaces and newlines becomes one space, but a space is never removed and never added where there was none. Text inside <pre>, <textarea>, <script>, <style> and <title>, inside SVG <text>, and inside any element whose style attribute sets white-space: pre, is copied exactly. Minified mode removes the whitespace that is not shown and every <!-- comment --> except conditional comments such as <!--[if IE]>; it can also drop quotes that are not needed and shorten disabled="disabled" to disabled. When tags overlap, as in <b><i>x</b></i>, or content sits directly inside a <table>, browsers rebuild elements and a new line break could change the result, so in that case the tool only re-indents whitespace that is already there. The tool cannot see your stylesheets: if CSS makes list items inline-block, or sets white-space: pre through a class, check those parts of the output.
Example input and output
<nav class="site"><ul><li><a href="/">Home</a></li><li><a href="/docs/">Docs</a></li></ul></nav><main><h1>Release notes <small>v2.1</small></h1><p>Builds are <strong>faster</strong> now.<br>Upgrade with:</p><pre><code>npm install example-cli@2.1</code></pre></main><nav class="site">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/docs/">Docs</a></li>
</ul>
</nav>
<main>
<h1>Release notes <small>v2.1</small></h1>
<p>
Builds are <strong>faster</strong> now.<br>
Upgrade with:
</p>
<pre><code>npm install example-cli@2.1</code></pre>
</main>Inline content such as Release notes <small>v2.1</small> stays on one line with its spaces, and a line break follows each <br>.
<p>Our plans:
<ul>
<li>Free</li>
<li>Pro</li>
</ul>
</p><p>Our plans:
<ul>
<li>Free</li>
<li>Pro</li>
</ul>
</p>
Line 2, column 3: <ul> closes the <p> opened on line 1
Line 6, column 1: </p> without an open <p>: browsers insert an empty paragraph hereA paragraph cannot contain a list, so browsers end the <p> before the <ul>, and the last </p> becomes an extra empty paragraph. The indentation shows the structure browsers build. Use a <div> instead of the <p>.
<article>
<!-- intro -->
<h2>Install</h2>
<p>Run <code>npm install</code> and <em>restart</em>
the server.</p>
<pre>
npm install
npm start</pre>
</article><article><h2>Install</h2><p>Run <code>npm install</code> and <em>restart</em> the server.</p><pre>
npm install
npm start</pre></article>The comment and the indentation between blocks are removed. The spaces around <code> and <em> stay (as one space each), and the <pre> block is kept exactly, newlines included.
Common errors and fixes
- Unclosed <span>: it is still open at </div>
- An element was not closed before its parent ended, so the browser closes it there for you. That is often harmless, but it can be a missing </span> in the wrong place, which makes the styling spill further than intended. Add the end tag where the element should end.
- </span> is ignored: <div> (line 1) is still open inside <span>
- Browsers ignore an end tag when a block element opened inside it is still open, so the <span> stays open and swallows what follows. Close the inner <div> first, or avoid putting a <div> inside a <span>.
- <ul> closes the <p> opened on line 1
- A paragraph can hold only text and inline elements. A <div>, <ul>, <table> or heading ends the open <p>, and a later </p> then creates an extra empty paragraph. Use a <div> as the container, or close the paragraph before the block.
- <script/> is not self-closing in HTML
- In HTML a "/" before > is ignored on elements that are not void, so <script src="app.js"/> stays open and treats the rest of the page as script; <div/> stays open too. Write <script src="app.js"></script>. Only void elements (<br>, <img>, <input> …) and SVG or MathML elements may end with />.
- <p> directly inside <table> is moved before the table
- Content in a table that is not inside a cell is "foster-parented": browsers move it in front of the table. Put it inside a <td> or <th>, or move it outside the table.
- </b> closes <b> while <i> (line 1) is still open
- The tags overlap: <b><i>x</b></i>. Browsers repair it by splitting and re-nesting elements, which may not be what you meant. Close the inner element first: <b><i>x</i></b>.
- Duplicate attribute class on <div>
- An attribute can appear only once per element. Browsers keep the first value and silently ignore the rest, so class="a" class="b" gives just class="a". Merge them: class="a b".
Common use cases
- Reading minified HTML from a build, a CMS export or View Source
- Finding the unclosed or stray tag that breaks a layout
- Tidying markup copied from DevTools, an email builder or a design tool
- Minifying an HTML snippet or email template without touching pre, script or style
- Checking a hand-edited page before a deploy
Privacy and security notes
- Your HTML is parsed and formatted by JavaScript in this browser tab. It is not sent to DevPrix or stored on a server.
- The markup is never rendered or run: the output is shown as highlighted text, so scripts, event handlers such as onerror, iframes and forms in it do nothing, and nothing it refers to (stylesheets, images, scripts, links) is fetched.
- Share copies a link that carries your input after the # in the URL. Browsers do not send that part to servers, but anyone you give the link to can read it, so do not share links that contain credentials or personal data.
Frequently asked questions
Will formatting change how my page looks?
It should not. Only whitespace changes, and only where it is not shown with the default CSS: next to block elements, between table cells and inside the head. Between inline elements a space stays a space (one, instead of several) and is never added where there was none, and <pre>, <textarea>, <script> and <style> are copied exactly. The tool cannot see your stylesheets, so if CSS gives elements a different display, for example inline-block list items whose gaps depend on the spaces between them, or sets white-space: pre through a class, check those parts. Inline style="display: …" and style="white-space: pre" are taken into account.
Why does it not add the missing </li>, </p> or </td>?
HTML allows those end tags to be left out: a new <li> ends the previous one, and a <div> ends an open <p>. The formatter never adds or removes tags, it only moves whitespace, so the output means exactly what the input meant. It indents the result the way browsers nest it and warns where an end tag is missing that the browser would have to guess, such as an unclosed <div> or <span>.
Why is a tag indented where I did not expect it?
The indentation follows the tree browsers build, not the tags as written. For example, <p>Intro<div>x</div></p> becomes a paragraph followed by a <div> at the same level, and a stray </p> that adds an empty paragraph; <span><div>x</span></div> keeps the <span> open, because browsers ignore that </span>. The Warnings list explains each case with its line and column.
What does minify remove?
Whitespace that is not shown, and comments, except conditional comments such as <!--[if IE]> and processing instructions such as <?php … ?>, which are usually server-side code. Turn on Keep comments to keep them all. Unquote attributes drops quotes that are not needed (class="btn" becomes class=btn), and Short booleans writes disabled="disabled" or disabled="" as disabled; both are off by default. Optional end tags are kept, and the code inside <script> and <style> is not minified: use the CSS Formatter for styles.
Can I format Vue, Svelte, JSX or template files?
The tool reads everything as HTML. Template syntax such as {{ name }}, {% if %}, <%= x %> and <?php … ?> is kept as text, so Handlebars, Liquid, Nunjucks, EJS and PHP templates format well. Framework components are different: in HTML <MyCard /> is an opening tag, so what follows would be nested inside it, and JSX is JavaScript, not HTML. Use Prettier or your framework's formatter for those.