Two spaces
The default here and in most modern front-end projects. Google's HTML/CSS style guide specifies it. Deep nesting stays on screen.
Two spaces is the usual answer, and HTML has a specific reason for it that other languages do not. Tabs have a better argument than they normally get credit for.
The default here and in most modern front-end projects. Google's HTML/CSS style guide specifies it. Deep nesting stays on screen.
More separation per level, easier to follow at a glance in shallow documents. Common in teams whose other languages already use four.
One character per level, rendered at whatever width the reader has configured. The only option that lets two people read the same file differently.
HTML nests deeper than most languages. A perfectly ordinary page reaches eight or nine levels before you
get to any content: html, body, div, main,
section, div, article, div, p. At four
spaces that paragraph starts at column 32 before a single word of text. Add an email template's nested
tables and you are past column 60.
That is the practical argument, and it is why two has won in the HTML world specifically even where the same teams use four elsewhere.
<html>
<body>
<div class="page">
<main>
<section>
<div class="wrap">
<article>
<div class="body">
<p>The content finally starts here.</p>
<html>
<body>
<div class="page">
<main>
<section>
<div class="wrap">
<article>
<div class="body">
<p>The content finally starts here.</p>
Tabs are the accessible option, and that argument deserves more weight than it usually gets. A developer with low vision working at large text sizes may need a wide indent to track nesting. A developer using a braille display generally wants a narrow one, because each indent character consumes a cell. With tabs, both set their editor once and read the same file comfortably. With spaces, the file decides for everyone.
The counter-argument is alignment. If you ever align something vertically that is not at the start of a line — a column of attribute values, say — tabs of different widths break the alignment. In practice, modern formatters do not do that kind of alignment, which weakens the objection considerably.
Tabs are also marginally smaller. One byte per level instead of two or four. On a large file that is a few kilobytes before compression and almost nothing after.
The difference between two spaces and four is a preference. The difference between a file with consistent indentation and a file with three styles in it is a real cost, paid every time anyone opens it.
Put an .editorconfig at the root of your project. Every major editor reads it, most without a
plugin, and it ends the discussion permanently:
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{{html,css,js}}]
indent_style = space
indent_size = 2
If your team uses Prettier, its config file plays the same role and takes precedence in the files it formats. Either way, the goal is the same: nobody should be deciding indentation by hand, ever.
Files that have passed through several editors end up with tabs on some lines and spaces on others. It is invisible until you open the file somewhere with a different tab width, at which point the structure appears to jump around at random.
The fix is one pass through a formatter. Paste the file into the panel on the front page, pick your indent style, format, and the output is uniform regardless of what went in — because the formatter rebuilds the indentation from the parsed structure rather than adjusting what was there.
If you are doing this to a repository, do it as its own commit with no other changes in it. A whitespace-only commit is easy to skip when someone is reading history; a whitespace commit tangled up with a logic change is a code review nobody can do properly.
Two spaces, and explicitly not tabs. That is in Google's HTML/CSS Style Guide, and it is the single most cited reason teams land on two.
Almost never. HTML collapses whitespace, so indentation between tags is invisible. The exceptions are inside <pre> and <textarea>, where every space is content — which is why a good formatter refuses to touch them.
Tabs, by one to three bytes per indented line. After gzip the difference is close to nothing. This is not a reason to choose either.
Format it with your preferred indent setting — the formatter discards the original indentation entirely and rebuilds it. Your editor can also do it: VS Code has Convert Indentation to Spaces in the command palette.
The formatter, minifier and validator are all on the front page.