Architectural Classification Matrix: Categorizing Invisible Characters by Structural Behavior
The 26 characters in the grid above fall into five families, and the family decides what a character can and cannot do far more than its name does. Sort by behaviour, not by appearance, and the right choice for any job becomes obvious.
Spaces (category Zs). Fourteen of the set are space separators, from the hair space at under a tenth of an em to the ideographic space at a full em. They share three traits: they render as visible blank, they never collapse in HTML the way a run of U+0020 does, and every one of them is removed by a standard trim. That last trait is why no space, however exotic, makes a reliable blank username.
Blank letters. The Hangul fillers (U+3164, U+115F, U+FFA0) and the Braille blank (U+2800) look empty but are classed as a letter or a symbol, not whitespace. They survive trimming and pass a “field must contain text” check, which is exactly what a blank name, bio or comment needs.
Zero-width marks. U+200B, U+200C, U+200D and the BOM take no horizontal space at all. They mark a wrap point, join or separate letters, or build emoji, and they are the characters most aggressively stripped by platforms, so they are unreliable for anything that must persist.
Format controls. The word joiner and soft hyphen carry an instruction to the line breaker rather than occupying space: never break here, or break here and show a hyphen. They are invisible until a line actually wraps.
Line breaks. U+2028 and U+2029 are the only members of categories Zl and Zp. They act as breaks in JavaScript, editors and text controls, though browsers do not render them as breaks in ordinary HTML.
| Character name | Hex code | HTML entity | Visual width | Validation bypass | Best real-world use |
|---|---|---|---|---|---|
| Space | U+0020 |
  |
~0.25 em | None | Ordinary word gap |
| No-Break Space | U+00A0 |
|
~0.25 em | Partial | Keep a number with its unit |
| Thin Space | U+2009 |
  |
~0.2 em | None | Group digits in long numbers |
| En Space | U+2002 |
  |
0.5 em | None | Fixed half-em gap |
| Em Space | U+2003 |
  |
1 em | None | Fixed one-em indent |
| Figure Space | U+2007 |
  |
1 digit | None | Align numbers in a column |
| Medium Math Space | U+205F |
  |
0.22 em | None | Plain-text formula spacing |
| Narrow No-Break Space | U+202F |
  |
~0.17 em | Partial | French punctuation spacing |
| Ideographic Space | U+3000 |
  |
1 em (full-width) | Partial | CJK layout and name fields |
| Hangul Filler | U+3164 |
ㅤ |
Invisible (letter) | Yes | Blank name, bio or comment |
| Braille Blank | U+2800 |
⠀ |
Invisible (symbol) | Yes | Blank that resists trimming |
| Zero Width Space | U+200B |
​ |
0 | None | Add a wrap point in a long word |
| Zero Width Joiner | U+200D |
‍ |
0 | None | Build emoji sequences |
| Word Joiner | U+2060 |
⁠ |
0 | None | Forbid a break between characters |
| Soft Hyphen | U+00AD |
­ |
0 until it breaks | None | Let a long word hyphenate |
| Line Separator | U+2028 |

 |
Line break | Partial | Multi-line in a one-line field |
| Paragraph Separator | U+2029 |

 |
Paragraph break | Partial | Paragraph break in editors |
The interactive grid at the top carries all 26, including the fractional-em spaces and the Hangul variants; this printed table is the quick-reference core. “Bypass” is shorthand: Yes means it passes an empty-field check because it is a letter, Partial means it slips past filters that block only the ASCII space, and None means a standard trim removes it.
Engineering Deployment Protocols: Picking the Right Hidden Character for the Job
For a blank that a form must accept
Use the Hangul Filler U+3164. It is the only character here that is both invisible and classed as a letter, so it survives trimming and passes “this field needs text”. The Braille blank is the backup when a platform rejects Hangul. Every space, including the full-width U+3000, fails this job, because a trim strips it. The Hangul Filler U+3164 Code and blank comment copy and paste pages cover the field-by-field details.
For a layout that must not break
Between two words, a no-break space (U+00A0) keeps “10 kg” together. Between two characters with no space, a word joiner (U+2060) stops a break with zero width, which is what holds “COVID-19” on one line. For a whole phrase, a span with white-space: nowrap beats a string of joiners. The no-break space and soft hyphen and word joiner guides have the wrap demos.
For a layout that should break cleanly
A soft hyphen (U+00AD) lets a long word break with a visible hyphen; a zero width space (U+200B) adds a break point with no hyphen, which suits URLs and file paths. Both are invisible until the break happens, so they do not disturb a line that fits.
For fixed-width alignment
Pick the space whose width matches the job: a figure space to align digits, an en or em space for a predictable indent, the ideographic space for a full CJK cell. The html space characters and space copy and paste pages measure each one live.
For auditing and cleanup
When text misbehaves, paste it into the invisible character detector to see every hidden character in place, then remove invisible characters to strip or normalise them. In code, the one-line fix for most input bugs is value.normalize('NFKC').replace(/[-]/g, ''): fold the exotic spaces to U+0020 and drop the zero-width set.
Frequently Asked Questions (FAQ): The Ultimate Technical Guide to Invisible Strings
Which single character should I reach for most often?
For a blank that sticks, the Hangul Filler U+3164. For layout that must stay on one line, the no-break space U+00A0. Those two cover the large majority of real tasks; the rest of the grid handles the edge cases.
Why do some of these vanish when I save a form?
The server runs a trim or a Unicode normalisation that removes whitespace and strips “default ignorable” characters. Spaces and zero-width marks go; letter-class blanks like U+3164 stay. The grid’s “Bypass” column predicts which survive.
Do any of these pose a security risk?
They are a data-hygiene risk more than an attack. Invisible characters can hide text in a copied string, break exact matching, and let a one-line field hold several lines. Treat every text input as untrusted: normalise with NFKC and strip the zero-width set before you store or compare it.
Can I combine several of these in one string?
Yes. Tick the rows you want and use Copy Selection to get them as a single string in the format you chose. It is the quickest way to build a test fixture that exercises every separator at once, or a decorative blank that mixes widths.
Are the widths in the grid exact?
They are measured live in your browser with the current font, so they reflect what your visitors actually see rather than a nominal spec value. Change your font or zoom and the numbers update on reload, which is the point: real rendering, not a chart.
The single most useful takeaway for the whole set
Classify before you copy: a space is for visible gaps and collapses out of blanks, a blank letter is for fields that need text, a zero-width mark is for wrap control and gets stripped, and the two separators are line breaks the browser ignores in HTML. Pick by behaviour and the right character is the obvious one.
Running an audit? Select the zero-width and line-break rows, copy them as one string, and paste that fixture into every field your app exposes.