CodeMirror indentation: choose inserted whitespace and tab display separately

In CodeMirror 6, configure indentUnit for the indentation string and EditorState.tabSize for the display width of tab characters. Language support supplies syntax-aware indentation, while commands such as indentMore and indentLess perform deliberate edits. A configuration change alone does not reformat the existing file. CodeMirror indentation reference

A support tool receives an HTML notice containing a tab before one paragraph and spaces before another. Its author wants new indents to use two spaces, while existing tabs remain readable at four-column stops. Those two decisions need separate settings; replacing every tab in the document would also risk changing preformatted content.

Configure the whitespace policy

For a CodeMirror 6 browser application with compatible packages:

import { EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { indentUnit, indentOnInput } from '@codemirror/language';
import { html } from '@codemirror/lang-html';

const view = new EditorView({
  doc: '<section>\n\t<p>Keep the original notice.</p>\n</section>',
  extensions: [
    EditorState.tabSize.of(4),
    indentUnit.of('  '),
    html(),
    indentOnInput()
  ],
  parent: document.querySelector('#notice-source')
});

The host page must already contain #notice-source. Merge these settings into the application's existing editor configuration rather than creating a second editor around an open document. The example uses two literal spaces for indentUnit; a tab-based policy would use indentUnit.of('\t') instead.

tabSize controls tab stops in the document view. It does not turn an existing tab into four stored spaces. indentOnInput() asks the active language's indentation rules to reindent relevant lines on supported input. It needs language information; installing it does not invent a parser for an arbitrary custom language. Indent-on-input API

Offer an explicit indentation action

An application can expose indentation without taking over the Tab key:

import { indentMore, indentLess } from '@codemirror/commands';

function increaseIndent() {
  indentMore(view);
  view.focus();
}

function decreaseIndent() {
  indentLess(view);
  view.focus();
}

Connect these functions to buttons labeled “Increase indentation” and “Decrease indentation.” Set their HTML type to button when they are inside a form. The commands operate on lines touched by the current selections. They are content edits, unlike changing a tab-stop preference.

If you also want Tab to indent, inspect the application's existing bindings and accessibility behavior. Do not capture Tab globally on the page. CodeMirror's Tab handling example explains its deliberate approach to keyboard focus, and the keymap guide covers precedence and commands that decline a shortcut.

Decide whether to shift lines or calculate structural indentation

Increasing the selected lines by one unit is a different operation from asking the language to calculate their appropriate indentation. Choose the command whose label matches the promised action. A “Format HTML” button implies more than adding two spaces to the start of a paragraph line.

For imported files, inspect the actual source before any broad conversion. Indentation within an HTML pre element or a script's string literal can have visible or semantic meaning. A blanket replacement is not a safe substitute for a syntax-aware formatter and a reviewed diff.

When the editor changes language or configuration during a session, use the CodeMirror compartment approach to preserve the document. Retain the author's text rather than rebuilding state merely to change an indentation preference.

Verify the characters written by the command

In a disposable document, select a line that starts without whitespace. Activate Increase indentation and inspect view.state.doc.toString(): the line should gain two spaces under this policy. Activate Decrease indentation and confirm the original line returns. Keep a second line with a literal tab and check that its stored tab remains until an intentional edit changes it.

Then type a small nested HTML section using the application's normal Enter bindings and inspect its real indentation. The outcome depends on language support and the surrounding setup, so do not infer it from the appearance of one existing line. Save the intended edits and compare the saved source with the current document string, including its actual tabs and spaces.

Keep reading