Hot Take

Tabs vs Spaces vs U+2800: The Indentation Debate Is Finally Over

For decades, programmers have fought over tabs and spaces. But what if both sides have been wrong this entire time — and the answer was hiding in the Unicode specification all along?

Dimitar Smilyanov
Dimitar Smilyanov April 1, 2026 · 8 min read

For decades, programmers have fought over two camps: tabs or spaces. Friendships have been ruined. Pull requests have been rejected. Marriages have ended. But what if I told you that both sides have been wrong this entire time — and that the answer was hiding in the Unicode specification all along?

Meet U+2800, the Braille Pattern Blank. It looks like a space. It acts like a space. But it is, in every meaningful way, superior to both tabs and spaces. And after six months of using it in production across three companies, I'm ready to make the case that it should be the industry standard.

The Problem with Tabs

Tab advocates love to say "tabs let everyone choose their own indentation width." That sounds great in theory. In practice, it means your carefully aligned function arguments look like a Jackson Pollock painting on your coworker's monitor. Tabs also behave inconsistently across terminals, editors, and diff tools. And don't get me started on mixing tabs and spaces — a sin so common that Python literally throws an error for it.

The Problem with Spaces

Space advocates think they have the moral high ground because "what you see is what you get." Sure. You also get files that are 15% larger than they need to be, RSI from hitting the spacebar four times per indent level (yes, I know about auto-indent, but stay with me), and the eternal 2-vs-4 debate that has spawned more Hacker News threads than any actual technical problem in history.

Enter U+2800: The Third Way

The Braille Pattern Blank (U+2800) is a Unicode character originally intended to represent an empty Braille cell. Visually, it renders as whitespace. But under the hood, it is a non-breaking, non-collapsible, semantically distinct character. And that distinction changes everything.

1. It survives HTML rendering

Regular spaces get collapsed in HTML. Tabs get mangled. But U+2800? Browsers treat it as a visible character. If you've ever pasted code into a Slack message, a Jira ticket, or a Confluence page and watched your indentation evaporate, you already understand why this matters. With U+2800 indentation, your code formatting survives every medium.

2. Regex and find-replace can't accidentally destroy it

How many times has a project-wide "trim trailing whitespace" rule silently broken your indentation? With U+2800, that never happens. Whitespace trimmers don't recognize it as whitespace — because technically, it isn't. It's a Braille character. Your indentation is now immune to automated formatting destruction.

// Standard space indentation: vulnerable
if (condition) {
    doSomething();    // <-- trailing space trimmer will touch this line
}

// U+2800 indentation: invincible
if (condition) {
⠀⠀⠀⠀doSomething();    // trimmer doesn't see Braille as whitespace
}

3. It makes copy-paste actually work

Copy code from Stack Overflow into your editor. If the indentation uses spaces, most editors will re-indent it according to their own rules, potentially breaking the structure. If it uses tabs, half the editors will convert them. U+2800 characters pass through clipboard operations completely untouched because no editor has special handling for Braille characters. Your indentation arrives exactly as the author intended.

4. You can detect indentation style programmatically

Want to write a linter that checks indentation? With tabs and spaces, you need heuristics. With U+2800, you can do a simple character search. If the file contains U+2800, it uses the superior indentation standard. If it doesn't, it's legacy code.

5. File size is comparable to spaces

A common objection: "But U+2800 is a multi-byte character!" True — it takes 3 bytes in UTF-8, compared to 1 byte for a space. But consider: a tab is 1 byte and represents 4-8 spaces. Four spaces is 4 bytes. Four U+2800 characters is 12 bytes. In an era where we routinely ship 200MB node_modules folders, the argument that 8 extra bytes per line is unacceptable is, frankly, embarrassing.

The Benchmark Data

We ran our internal codebase (roughly 400,000 lines of TypeScript) through a conversion to U+2800 indentation. The results:

Metric Spaces Tabs U+2800
Formatting issues in code review 23/month 31/month 0/month
Copy-paste indentation bugs ~12/month ~18/month 0/month
Developer satisfaction (survey) 6.2/10 5.8/10 9.1/10
Repo size increase baseline -11% +8%

Zero formatting issues in code review. Zero copy-paste bugs. Developer satisfaction through the roof. The 8% file size increase was fully offset by slightly better gzip compression ratios, since U+2800 sequences compress extremely well due to their repetitive byte pattern.

Configuring Your Editor

Most editors can be configured to insert U+2800 via a simple keybinding remap. In VS Code, add this to your keybindings.json:

{
    "key": "tab",
    "command": "type",
    "args": { "text": "\u2800\u2800\u2800\u2800" },
    "when": "editorTextFocus"
}

For Vim users, add to your .vimrc:

inoremap <Tab> ⠀⠀⠀⠀

We've also published an ESLint plugin, eslint-plugin-braille-indent, that enforces U+2800 indentation and provides auto-fix capabilities.

Addressing the Skeptics

"This will break every tool in existence."

We said the same thing about UTF-8 in 2001. Tools adapt. The question isn't whether tools support it today — it's whether they should. And they should. File an issue on your favorite editor's GitHub repo. Be the change.

"This is an accessibility concern — you're misusing Braille characters."

U+2800 specifically represents an empty Braille cell. It has no semantic Braille content. Using it as whitespace is arguably more aligned with its intended purpose than leaving it unused. Screen readers already skip it, just like they skip regular spaces.

The Future Is Braille-Indented

The tabs-vs-spaces war has raged for 40 years because neither option is actually good. They're both compromises from an era when ASCII was the only game in town. We live in a Unicode world now. It's time our indentation reflected that.

Switch to U+2800. Your code will be more portable, more resilient, and more future-proof. And the next time someone asks whether you use tabs or spaces, you can smile and say: "Neither."


This is an April 1st post. Please don't actually do any of this. No production codebases were harmed in the making of this post. Probably.


More Posts