Skip to content

Visible whitespace

A code block usually renders whitespace as empty space. That is fine for most languages, but some depend on the exact character. Make needs a tab at the start of a recipe, and Python needs consistent indentation. The whitespace attribute shows spaces and tabs as glyphs, so readers see which character is there.

Readers see

Makefile
build:
cargo build --release
test:
cargo test # Recipes must start with a tab

You write

```make title="Makefile" whitespace
build:
cargo build --release
test:
cargo test # Recipes must start with a tab
```

The first recipe starts with an arrow, for the tab that Make needs. The second starts with four dots, for the four spaces that Make rejects. Copying the block gives the real characters, not the glyphs.

Syntax Where Effect
whitespace Code block fence line Shows the leading whitespace of every line
whitespace="all" Code block fence line Shows every space and tab in the block

whitespace="all" shows every space, which is useful when trailing whitespace is part of what you are explaining:

diff.patch
- const width = 10;
+ const width = 12;
  • The glyphs:
    • A space renders as a middle dot. A tab renders as an arrow at the start of the tab. The tab keeps its width up to the next tab stop. The plugin sets the CSS tab-size property of code blocks to 2 columns.
    • By default, the plugin shows only the leading whitespace of each line, where indentation usually matters. whitespace="all" shows every space and tab, including the ones between words and at the end of a line.
    • The glyphs are faint, so that they do not compete with the code. They use the text colour of the theme at about a third of its strength.
  • Screen readers:
    • Screen readers do not hear the glyphs. They read the same code as a block without the attribute.
  • Copy:
    • The glyphs are drawn with CSS on top of the real character. A manual copy or the copy button gives the actual spaces and tabs.
  • Without JavaScript:
    • Visible whitespace needs no JavaScript in the browser.

Visible whitespace has no options. Turn it off for the whole site with whitespace: false:

astro.config.mjs
codeblocks({
whitespace: false,
});

The style setting codeblocksWhitespace.foreground changes the colour of the glyphs.

  • The glyphs add visual noise on a block with a lot of whitespace. Use whitespace="all" only where the extra detail matters, and leave the default, leading-only view for everything else.
  • Expressive Code removes the whitespace at the end of each line before any plugin sees the code. The plugin puts it back for fenced code blocks in Markdown and MDX. A block that the <Code> component renders does not show trailing whitespace.
  • Expressive Code turns every tab into spaces before this feature can see it. codeblocks() sets tabWidth: 0 for you unless you already chose your own value. A site without Starlight sets tabWidth: 0 in ec.config.mjs itself. A tab then reaches the plugin unchanged, and a Makefile block copies its real tab rather than spaces. Set expressiveCode.tabWidth in the Starlight config, or tabWidth in ec.config.mjs, for Expressive Code’s normal tab-to-space expansion instead.
  • Line states: mark the line that has the indentation problem, with a message that explains it.