Skip to content
Free Tool Arena

How-To & Life · Guide · Developer Utilities

How to format HTML

Indentation rules, self-closing tags, attribute order, minification trade-offs, and how to keep hand-edited HTML readable in version control.

Updated April 2026 · 6 min read

HTML that lands in your repo after a copy-paste from a CMS, a WYSIWYG editor, or a code generator is almost always ugly: inconsistent indentation, closing tags jammed against content, attributes scattered in random order, and self-closing tags that disagree with the project’s conventions. The browser does not care—it will parse almost anything that looks like HTML—but humans and diff tools care a lot. Consistent formatting keeps reviews fast, makes diffs meaningful, and surfaces structural bugs that messy HTML hides. This guide covers indent size, attribute ordering, self-closing and void elements, how Prettier differs from html-tidy, inline versus block-level rules, and the specific conventions that make HTML readable at scale.

Advertisement

Indent size and character

Two-space indentation is the modern default for HTML, matching the JavaScript and CSS ecosystem. Four-space and tab indentation are still common in older codebases and some enterprise style guides. The absolute rule is consistency: mixed tabs and spaces break diff-tool alignment and trigger noisy whitespace changes on every commit. Configure your editor with editorconfig or a Prettier config so every contributor produces the same output, and add a pre-commit hook that runs the formatter on changed files.

.editorconfig
[*.html]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

Void elements and self-closing syntax

HTML5 has 14 void elements that never have a closing tag: area,base, br, col, embed, hr,img, input, link, meta, param,source, track, and wbr. The HTML5 spec allows both<br> and <br /> and treats them identically, but project style usually picks one. Plain <br> is the HTML5 idiom. Self-closing<br /> is a holdover from XHTML but remains common in JSX-adjacent codebases where developers want one consistent rule across both languages. Pick one and enforce it with the formatter.

Block versus inline elements

Block-level elements (div, section, article,header, footer, p, h1-h6,ul, ol, li, table) go on their own line with their children indented one level. Inline elements (span, a,em, strong, code) stay on the same line as surrounding text so the prose reads naturally. Breaking inline elements onto their own lines can introduce unintended whitespace nodes that change rendering, especially in flex and grid layouts where a stray space affects alignment.

<p>This is <a href="/">a link</a> in a sentence.</p>

Not:
<p>
  This is
  <a href="/">a link</a>
  in a sentence.
</p>

Attribute ordering

No official spec mandates an attribute order, but consistent ordering makes scanning faster and helps reviewers spot missing values. A widely used order is: structural attributes first (id, class), then element-specific attributes (href,src, type, value), then metadata (name,title, alt, role, aria-*), then event handlers (onclick), then data-* attributes last. Prettier does not sort attributes by default, but the prettier-plugin-organize-attributes plugin and many linters can enforce an order if your team picks one.

Attribute wrapping

When a tag has more attributes than fit on a single line at the project’s print-width setting (usually 80 or 100 characters), wrap each attribute onto its own line with the closing bracket on a new line. Prettier does this automatically whensingleAttributePerLine is enabled or when the line would exceed the print width.

<button
  type="button"
  class="btn btn-primary"
  data-action="submit"
  aria-label="Save changes"
  disabled
>
  Save
</button>

Quote style for attributes

HTML5 accepts unquoted attribute values for values that contain no whitespace, quotes, ampersands, equals signs, or angle brackets. Quoted values are universally safer and are the norm in every modern style guide. Double quotes are the default. Single quotes work but can collide with JavaScript string content when HTML is embedded in JS templates. Pick double quotes and lock it in your formatter.

Boolean attributes

HTML boolean attributes like disabled, checked,readonly, required, selected, and hiddenare true when present and false when absent regardless of value. You can write them asdisabled, disabled="", or disabled="disabled"and all three mean the same thing. The bare-name form is the modern idiom. Do not writedisabled="false"—it is still true, because the attribute exists, and the string “false” is ignored. To make the input not disabled, remove the attribute entirely.

Prettier versus html-tidy versus js-beautify

Prettier is the modern default: fast, opinionated, minimal configuration, and handles embedded CSS and JavaScript consistently. It formats HTML as part of a project-wide formatter covering many languages. html-tidy is the classic tool: very configurable, good at repairing malformed HTML, but slower and more opinionated in weird directions. js-beautify (with its HTML mode) sits between them with more knobs than Prettier and faster operation than tidy. For new projects Prettier is the path of least resistance; for legacy cleanup where you need to repair broken HTML, html-tidy is better.

Preserving meaningful whitespace

Inside <pre>, <textarea>, and any element withwhite-space: pre in CSS, whitespace matters. Formatters must leave these contents alone—no reindentation, no collapsing, no trailing-whitespace trimming. Prettier and html-tidy both respect this by default. If you see formatter output that adds or removes leading spaces inside a <pre>, check for a formatter bug or a misconfigured override.

Common mistakes

Reformatting generated files. Template engines, bundlers, and CMS exports all produce HTML that may have intentional structure. Running a formatter on build-output HTML creates noise that obscures real changes. Format source, not output.

Breaking inline text across lines. Putting <a> or<em> tags on their own line adds whitespace nodes that change rendering in flex and grid layouts. Keep inline elements on the same line as surrounding prose.

Mixing self-closing styles. Some <br /> and some<br> in the same file means the formatter is not running or is misconfigured. Pick one and enforce it.

Manual indentation on a large file. Humans are bad at counting spaces. Always run the formatter before committing instead of adjusting indentation by eye.

Writing disabled="false". A present boolean attribute is always true. Remove the attribute to make it false.

Unquoted attribute values. Technically legal for simple values but brittle the moment someone adds a space or a quote. Always quote attribute values.

Run the numbers

Clean up messy HTML instantly with the HTML formatter. Pair with the XML formatter for XHTML and XML-flavored markup where whitespace and self-closing rules differ, and the HTML to Markdown converter when you decide the content would be better expressed as Markdown once it is legible.

Advertisement

Found this useful?Email