To remove HTML source indentation from a displayed code block, remove the shared leading spaces from its text while preserving relative indentation. Keep preformatted whitespace enabled so nested lines and deliberate spacing remain readable.
This guide is for someone editing a small HTML page on a Mac and previewing it in a desktop browser. The task is to remove the indentation introduced by the surrounding page layout without flattening the code inside it.
Why does HTML indentation appear inside a code block?
A pre element represents preformatted text, and WHATWG explicitly supports combining it with a code element for computer code. Consequently, spaces used to indent the example within your HTML file can become part of the displayed example. HTML Standard: The pre element.
Consider this HTML fragment from a synthetic page containing a panel example. Every content line has eight unwanted leading spaces; the two property lines have another two spaces that should remain.
<pre><code> const panel = {
label: "Panel A",
count: 2
};</code></pre>
The desired displayed text is:
const panel = {
label: "Panel A",
count: 2
};
The browser has one relevant parsing exception: it removes a single newline immediately after an opening pre tag. That exception does not remove common indentation, and a newline after an intervening code start tag is not immediately after pre. MDN also explains that literal markup characters in preformatted text still require appropriate escaping. MDN: The preformatted text element.
Choose the fix that matches the unwanted space
Before changing the page, distinguish text indentation from the spacing around the element. This decision sequence helps avoid fixing the wrong layer.
| What you observe | What to inspect | Appropriate action |
|---|---|---|
| Every content line starts with extra space characters | The code element’s text | Remove only the common leading indentation |
| The text starts correctly, but the whole box is inset | The element’s CSS and its container | Adjust the relevant layout spacing |
| There is an empty line before or after the example | Newlines around the actual content | Remove that specific newline if unintended |
| Long lines extend beyond the box | Wrapping behavior | Choose preserved lines or wrapping separately |
| The example already uses Prism | Its whitespace plugin configuration | Consider Normalize Whitespace |
For a single static example, the simplest correction is to edit the content directly: start its first line immediately after the opening code tag and remove the unwanted shared spaces from subsequent lines. Keep any indentation that belongs to the example itself. The surrounding page markup can remain indented independently.
For repeated examples, normalize their source text during page generation or before syntax highlighting. The next section demonstrates the calculation explicitly so you can see which spaces disappear.
Why changing white-space is insufficient
CSS white-space: pre preserves spaces and line breaks without ordinary wrapping. pre-wrap preserves whitespace while allowing wrapping. pre-line preserves line breaks but collapses sequences of spaces; normal also collapses source newlines. These controls do not selectively subtract the shared indentation of a code example. MDN: white-space.
For this task, use pre when preserving each source line matters, or pre-wrap when fitting long lines matters more. Removing shared indentation is a separate text operation.
W3C’s CSS Text Level 4 draft defines white-space-trim, but its preformatted-block example explicitly retains indentation within the actual content. MDN currently documents that property as unimplemented in browsers. It therefore provides neither a supported browser solution nor the common-indent calculation needed here. W3C: White Space Trimming, MDN: white-space constituent properties.
Use a complete example that preserves nested indentation
The following standalone HTML document requires no library or build tool. In your Mac code editor, save it as a plain-text file named indent-demo.html, then open that file in your desktop browser. The script appears after the example, so the target element already exists when the script runs.
The demonstration deliberately starts the content on the same line as the opening code tag. It also leaves a final newline before the closing tag. The function preserves that final newline rather than silently trimming the example.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Code indentation example</title>
<style>
body {
max-width: 48rem;
margin: 2rem auto;
padding: 0 1rem;
font-family: system-ui, sans-serif;
}
pre {
padding: 1rem;
background: #f2f2f2;
white-space: pre;
overflow-x: auto;
}
code {
font-family: monospace;
}
</style>
</head>
<body>
<h1>Panel example</h1>
<pre><code id="panel-example"> const panel = {
label: "Panel A",
count: 2
};
</code></pre>
<script>
function dedentSpaces(text) {
const lines = text.replace(/\r\n?/g, "\n").split("\n");
if (lines.some(line => /^[ \t]*\t/.test(line))) {
throw new Error(
"Use spaces for leading indentation before dedenting."
);
}
const contentLines = lines.filter(line => /[^ ]/.test(line));
if (contentLines.length === 0) return lines.join("\n");
const indent = Math.min(
...contentLines.map(line => line.match(/^ */)[0].length)
);
return lines.map(line => {
const leadingSpaces = line.match(/^ */)[0].length;
return line.slice(Math.min(indent, leadingSpaces));
}).join("\n");
}
const code = document.getElementById("panel-example");
code.textContent = dedentSpaces(code.textContent);
</script>
</body>
</html>
The function finds the smallest number of leading spaces among nonblank lines. For this illustrative input, the counts are eight, ten, ten and eight. Subtracting eight leaves zero, two, two and zero: the object’s internal indentation survives.
Blank lines do not lower the minimum to zero. On a blank line, the function removes at most the shared number of spaces and keeps the line break. It also leaves trailing spaces on content lines untouched. These choices make the transformation narrower than applying trim() to every line, which would remove the nested indentation.
The implementation intentionally normalizes CRLF and CR line endings to LF. It rejects tabs in leading indentation instead of guessing how many displayed columns each tab represents. An entirely space-only input is returned with its spaces retained, apart from that explicit line-ending normalization.
The dedent function was run in Node.js against five deterministic output cases covering nested indentation, blank lines, an unindented line, CRLF input and space-only input. A separate check confirmed rejection of leading tabs. Those checks validate the string transformation; they do not constitute a browser rendering test.
Apply the transformation before highlighting
The example reads and writes textContent. MDN documents that reading this property collects descendant text, while setting it replaces the element’s children with a text node. Therefore, run this transformation before a syntax highlighter adds token elements; applying it afterward would remove that highlighting markup. MDN: Node.textContent.
For an existing page, keep the function but replace the demonstration’s ID with the actual code element’s ID. Select only the intended example. If a page renderer later replaces that element, place normalization in that renderer’s preparation step so the displayed content receives the transformation.
If the page already uses Prism, use its whitespace plugin
Prism provides a named Normalize Whitespace plugin for block examples using pre and code. Its documented remove-indent option removes excess indentation. Its defaults also trim the block’s beginning and end and remove trailing whitespace, which is a broader edit than the function above. Prism: Normalize Whitespace.
With Prism and Normalize Whitespace already loaded, the following configuration fragment keeps indentation removal enabled while disabling those three additional default cleanup operations. Apply it before highlighting the target examples.
// Configuration fragment: Prism and its plugin must already be loaded.
Prism.plugins.NormalizeWhitespace.setDefaults({
"remove-indent": true,
"remove-trailing": false,
"left-trim": false,
"right-trim": false
});
These defaults affect plugin behavior beyond a single example. Prism also documents per-block settings through data- attributes and the no-whitespace-normalization class for opting a block out. Inspect existing settings before adding another normalization pass. Prism: Normalize Whitespace usage.
Check the result without changing the code’s meaning
On a Mac using Chrome, press Command + Option + J to open the Console. After opening the standalone demonstration, run the following inspection expression. Chrome documents this shortcut in its DevTools reference. Chrome DevTools: Keyboard shortcuts.
JSON.stringify(document.getElementById("panel-example").textContent)
The returned string should contain the text below. The \n sequences make the line breaks visible; there should be no spaces before the first const, two before each property and none before the closing brace.
"const panel = {\n label: \"Panel A\",\n count: 2\n};\n"
Then check the displayed example and copy it into a plain-text editor. Confirm that the first line starts correctly, nested lines retain their indentation, and intentional blank lines remain. If the text is correct but the box still appears inset, return to its layout styles rather than deleting more characters.
A nonblank line with zero leading spaces makes the function remove nothing. That is deliberate: one unindented line means there is no indentation shared by every content line. Inspect that line before choosing a fixed removal amount.
Finally, common indentation is an editorial assumption, not something this function can infer from program syntax. Avoid automatic dedenting when leading spaces are meaningful sample data, part of a multiline string, or deliberate alignment in a diagram. For those examples, prepare the intended display text explicitly.
For an ordinary code example, the reliable workflow is to identify the shared source margin, remove that margin once, and leave the remaining text to the browser’s normal rendering. Keep wrapping and container spacing as separate decisions, then verify both the visible block and its underlying text.
Sources
- HTML Standard: The pre element — WHATWG.
- The preformatted text element — MDN Web Docs.
- white-space — MDN Web Docs.
- CSS Text Module Level 4: White Space Trimming — W3C.
- Node: textContent property — MDN Web Docs.
- Normalize Whitespace — Prism.
- Keyboard shortcuts — Chrome for Developers.