Paste HTML and get it back indented, or minified if you are going the other way. Use it on a saved page, or on template output that arrived from a CMS as one long line. Format keeps inline elements such as links on the same line as their text, so the rendered spacing does not change.
<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Hello World</h1><p>This is a test.</p><div><ul><li>Item 1</li><li>Item 2</li></ul></div></body></html> <!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World</h1>
<p>This is a test.</p>
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
</body>
</html> Generated markup often arrives as a single line. Indented, the nesting is visible, and a missing closing tag shows up as a block that never steps back out.
Format both versions before you diff them. With the same indentation on each side, the diff shows only the lines whose content changed.
// npm i js-beautify
const { html: beautify } = require("js-beautify");
const raw = "<div><p>Hello <b>world</b></p><ul><li>One</li><li>Two</li></ul></div>";
console.log(beautify(raw, {
indent_size: 2,
wrap_line_length: 0,
unformatted: ["b", "i", "code", "span"], // keep inline elements on one line
}));
// Minify: strip comments and whitespace between tags
console.log(raw.replace(/<!--[\s\S]*?-->/g, "").replace(/>\s+</g, "><").trim()); This is the library behind the tool itself. It runs in Node.js and as a browser bundle.
<?php
$html = '<div><p>Hello <b>world</b></p><ul><li>One</li><li>Two</li></ul></div>';
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
// The flags stop libxml wrapping the fragment in <html><body> and a doctype
libxml_use_internal_errors(true);
$doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
echo $doc->saveHTML(); libxml's HTML serializer puts each block element on its own line but does not indent nested elements. For real indentation, use tidy (ext-tidy).
# pip install beautifulsoup4
from bs4 import BeautifulSoup
raw = "<div><p>Hello <b>world</b></p><ul><li>One</li><li>Two</li></ul></div>"
soup = BeautifulSoup(raw, "html.parser")
print(soup.prettify()) # one tag per line, indented
# Minify
import re
print(re.sub(r">\s+<", "><", str(soup)).strip()) prettify() puts every tag on its own line, inline ones like <b> included, which changes the whitespace the browser renders. Use it for reading, not for output you ship.
Keep inline elements on the same line as their text. HTML's whitespace rules are why a formatter can change what a page looks like. Between block elements whitespace is ignored, so newlines and indentation there cost nothing. Inside inline content, any run of whitespace collapses to one space, and that space is rendered.
Minifying HTML saves less than you would expect once gzip or brotli is involved, because runs of whitespace compress to almost nothing. It still helps on very large pages, and it strips comments you would rather not ship to users.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Format changes only whitespace and indentation, and it keeps inline elements on the same line as their text. The contents of pre and textarea keep their spacing. Minify, however, is a plain whitespace collapse: it also squeezes pre blocks and inline scripts, so a script with // comments will break.
Yes. The Minify button removes comments and the whitespace between tags, and collapses other runs of whitespace to one space.
No. It formats what you give it and does not close tags or repair structure. Run the result through the W3C validator when you need a correctness check.
The dropdown offers 2 Spaces, 4 Spaces or Tab.
Yes, with Load URL, if the server allows cross-origin requests. Otherwise save the page and use Upload File.
The CSS formatter does the same for stylesheets, and Purge CSS uses your markup to work out which rules are dead.