
Every button above writes exactly one invisible character to your clipboard. The plain zero width space most searches mean is the first row, U+200B, and after copying you can paste it into the verify field to confirm the clipboard holds one codepoint and not three. That check is the reason this page has a second step, because the one thing an invisible character will never do is show you what you actually grabbed.
What a copied U+200B is good for
A zero width space marks a position where a line may break without showing a hyphen or a gap. That makes it the fix for long unbroken strings that blow up a layout, URLs in running text, breadcrumbs, file paths in a table cell, a 60-character order ID in an email. Drop one after each slash or dot and the string wraps where you decided instead of overflowing.
The second everyday use is defusing pattern matchers. A zero width space after the @ keeps a handle from pinging the person when you quote them, and one inside a domain keeps an example URL from turning into a clickable link. The matcher sees an interrupted pattern and gives up, the reader sees nothing.
Its typographic cousin, the soft hyphen U+00AD, does the same job for long words instead of long strings. It stays invisible until the line actually breaks at it, and then it renders as a hyphen, which is what you want in a headline with "Donaudampfschifffahrt" in it and never in a database column.
Both zero-width uses work because U+200B is not whitespace. JavaScript's trim() leaves it in place and \s never matches it, so it survives the cleanup passes that would eat an ordinary space.
Anywhere a string is later compared, hashed or used as a key, keep it out.
ZWSP, ZWNJ, ZWJ or word joiner
The four characters at the top of the list render identically, as nothing, and mean four different things. U+200B allows a line break. U+2060 word joiner forbids one, useful in front of a unit or inside a version number you never want split across lines. U+200C, the non-joiner, stops two letters from forming a joined shape, which is spelling-relevant in Persian, Arabic and Hindi and also the polite way to break an unwanted ligature. U+200D, the joiner, is the glue of modern emoji.
That last one carries more weight than its name suggests. A three-person family emoji is three emoji with a zero width joiner between each pair, eight UTF-16 units that Intl.Segmenter counts as a single grapheme. Delete the joiners and the family falls apart into individuals. So a blanket strip of everything zero width is never a safe cleanup, which the guide to invisible Unicode characters walks through along with where these characters sneak in uninvited.
On the clipboard all four are the same three bytes of nothing to your eyes, which is how the wrong one ends up in a test fixture. Copy, paste into the verify field, read the codepoint. Three seconds against an afternoon of confusion.

0xFEFF, the character with two jobs
People rarely search for U+FEFF by its Unicode spelling. It shows up in error output and hex dumps as 0xFEFF, the same value written as a number, or as the bytes EF BB BF at the start of a file, and that is how it gets typed into a search box.
The character has two jobs depending on position. At the very start of a file it is the byte order mark, an encoding signature that Windows editors and Excel exports like to write. Anywhere else it is a leftover zero width no-break space, a formatting character from before Unicode 3.2 handed that job to U+2060. Copying it from this page is mostly useful for building test cases, a fixture that starts with 0xFEFF is the fastest way to prove your pipeline survives real-world CSV exports.
What it does to parsers is measurable. In Node 22, JSON.parse on a document with a leading BOM throws immediately, and the message quotes the offending token verbatim.
Mid-text U+FEFF is nastier than the file-start case because nothing expects it there. It arrives when someone concatenates files without stripping BOMs, and it breaks string comparisons exactly like a zero width space while being missed by cleanup regexes that only target the U+200B block.
Hangul filler and the braille blank
The last two characters in the list are not zero width at all. Both occupy space and draw nothing, and both explain why a validator that only checks for whitespace misses them.
U+3164 is a filler from the Hangul compatibility block, a placeholder that occupies a letter slot without drawing anything. Unicode classifies it as a letter, category Lo, so a "must contain a letter" rule is satisfied, a whitespace check finds nothing to object to, and trim() leaves it alone. The validator was asking about categories and the category is fine. What it should ask is whether anything remains after NFKC normalisation and filler removal. NFKC maps U+3164 to the older filler U+1160, which is why two "identical" invisible names can still collide or still differ depending on what the platform normalises.
U+2800 is the braille pattern with zero dots raised. It is a symbol, not whitespace and not a letter, so a trim and an "at least one letter" rule both let it through, and a chat app that trims a message before checking for emptiness ends up sending a blank one. A validator that wants to catch it has to test for visible glyphs, not for categories.
Worth saying plainly, both gaps get patched. If a name matters, do not build it on a filler character.
Where an invisible character bites back
The classic interview puzzle "why don't these two identical strings match" is usually this character. It is also a genuinely fair question, because the debugging move it teaches is the one that works in production, stop trusting your eyes and print the codepoints.
$ node -e "console.log('a\u200Bb'.length, [...'a\u200Bb'].length, 'a\u200Bb' === 'ab')" 3 3 false
The length is 3, the codepoint count is 3, and the string never equals its visible twin. The same maths applies to JSON keys, a key of a parses fine and then obj.a is undefined, to environment variables, to API tokens pasted from a chat window, and to database values that suddenly produce duplicate-looking rows a unique constraint happily accepts.
The characters also travel in disguise. %E2%80%8B, %E2%80%8C and %E2%80%8D in a URL or an access log are the percent-encoded UTF-8 of the zero width space and the two joiners, encodeURIComponent('') returns exactly those nine characters. The escapes column in the tool shows every character in all three notations, so a strange log line can be matched back to its codepoint by eye.
I keep one U+200B in a test fixture at work on purpose, as a canary for exactly this class of bug. The price is real, every new colleague loses half an hour to it once.
Getting them out again
Removal is a different job. The third field on this page strips every named invisible character out of a pasted text and tells you how many went, which covers the quick case. For positions, a line and column per hit and a full report, paste the text into the invisible character detector instead. If you copied a character here and just want it gone from one word, delete the word and retype it, which beats hunting for a single invisible position.
Copying and typing invisible characters
How do I type or insert a zero-width space on purpose?
Write it as an escape wherever the file format allows one, \u200B in JavaScript, Python and Java, ​ or ​ in HTML. In Word, type 200B and press Alt+X. On Linux, Ctrl+Shift+U followed by 200b works in apps using IBus. When you copy it as a bare character instead, paste it into a verify field first, because ZWSP, ZWNJ and word joiner are indistinguishable on the clipboard and each means something different.
Why does an invisible username pass validation?
Because the validator asks the wrong question. A "must contain a letter" rule checks the Unicode category, and U+3164, the Hangul filler, is a letter by category while drawing nothing, so the check passes. A trim() or \s check does not catch it either, since it is not whitespace. The fix on the validating side is to normalise with NFKC first, which turns U+3164 into U+1160, and then to reject names that are empty after removing format and filler characters. The fix on the signup side is to expect that exact patch to arrive one day.
Does a zero width space count as a character?
Yes. In JavaScript "a\u200Bb".length is 3, Python counts it too, and it spends three bytes of any UTF-8 length limit.
What is the HTML entity for a zero width space?
​ numerically or ​ by name. The joiners are ‌ and ‍, the soft hyphen is ­.
Why does my JSON fail with an invisible character?
Two different ways. A byte order mark before the first brace is not valid JSON, and Node 22 reports it as an unexpected token while quoting a character you cannot see. A zero width space inside a string parses without complaint but poisons the data, a key of a plus U+200B prints as a and never matches obj.a. Between tokens it is a plain syntax error. When the reported position looks blameless, inspect the bytes at that spot rather than the characters.
How do I stop a URL or @mention from turning into a link?
Break the pattern the autolinker matches, a zero width space after the @ or inside the domain interrupts it. The trade is that the text is no longer the real handle or address, so nobody can copy and use it directly, and an app that strips invisible characters on paste relinks it anyway. Test it in the app that matters.
Is U+FEFF the same as a zero width space?
No. U+FEFF began as the zero width no-break space, the opposite of U+200B in break behaviour, and since Unicode 3.2 that formatting job belongs to U+2060 word joiner while U+FEFF is reserved for the byte order mark. For an invisible character that forbids a break, copy U+2060, not 0xFEFF.