How to use this Unicode Converter
Paste or type text into the input box, then choose whether you want to encode it into
Unicode escape sequences or decode escaped Unicode back into readable text.
- Enter text or Unicode escape sequences into the input box.
- Click Text to Unicode to encode text.
- Click Unicode to Text to decode Unicode escapes.
- Copy or download the output if needed.
Example conversion
Input: Hello
Output: \u0048\u0065\u006C\u006C\u006F
Common use cases
- Debugging encoded strings
- API payload inspection
- Source code preparation
- Unicode escape decoding
- Text transformation workflows
Code point, code unit, and grapheme cluster
Almost every Unicode bug comes from blurring three different things that all get loosely
called "a character." A code point is a Unicode scalar value — the abstract
item the standard assigns, such as U+0041 for A or
U+1F600 for 😀. A code unit is the fixed-size
piece the chosen encoding stores data in: UTF-16 uses 16-bit units, UTF-8 uses 8-bit bytes.
A grapheme cluster is what a human perceives as one character, which may be
built from several code points — a base letter plus combining marks, or an emoji assembled
from several scalars joined together.
These three rarely line up. One grapheme can be several code points, and one code point can
be several code units. Keeping them distinct is what lets you predict why a length looks
"wrong," why a slice cuts a character in half, or why two strings that look identical fail
an equality check.
Why "😀".length is 2 in JavaScript
JavaScript's String.length counts UTF-16 code units, not
characters and not code points. The grinning-face emoji sits at U+1F600, above
U+FFFF, in what Unicode calls the supplementary (or astral) planes. Anything
above U+FFFF cannot fit in a single 16-bit unit, so UTF-16 stores it as two
units — a surrogate pair — and length dutifully reports 2.
If you iterate the string in a way that walks code points instead — a
for...of loop, the spread [...str], or
Array.from(str) — the emoji counts as one. That is why
[..."😀"].length is 1 while
"😀".length is 2. Neither, though, matches what a user
counts as characters once combining marks and joined emoji enter the picture; for that you
need grapheme segmentation via Intl.Segmenter with granularity
'grapheme'.
Surrogate pairs, and why slicing breaks emoji
Code points from U+10000 to U+10FFFF are encoded in UTF-16 as two
special units: a high surrogate in the range
U+D800–U+DBFF followed by a low surrogate in
U+DC00–U+DFFF. Neither half is a valid character on its own; they only mean
something as a pair.
This is exactly why naive string handling mangles emoji. Indexing or slicing by code-unit
position — str[i], or a slice() that lands on an odd boundary —
can cut a surrogate pair down the middle, leaving a lone surrogate that is invalid and
renders as the replacement character � (�). Truncating a user's text to
"the first 20 characters" with a raw index is the canonical way to produce a trailing �.
Splitting on code points (or graphemes) instead keeps every character whole.
NFC vs NFD: why identical-looking text compares unequal
The letter é has two legitimate Unicode spellings. It can be the single
precomposed code point U+00E9 (normalization form NFC), or it
can be a plain e followed by U+0301, the combining acute accent
(form NFD). On screen they are indistinguishable, but they are different
sequences of code units, so a naive === returns false and even
.length differs — 1 versus 2.
This is a real, recurring production trap. Apple's HFS+ and APFS filesystems have
historically stored filenames in NFD, while most other systems and web content use NFC, so
text copied between them can silently fail equality checks, searches, and de-duplication.
The fix is to normalize before you compare, store, hash, or generate a slug: call
str.normalize('NFC') on both sides first so the same visible text is guaranteed
to be the same bytes.
UTF-8 is variable-width: four numbers for one string
UTF-8 encodes each code point in one to four bytes. ASCII characters take 1 byte; most
Latin, Greek, and Cyrillic letters take 2; the rest of the Basic Multilingual Plane,
including most CJK characters, takes 3; and emoji and other astral characters take 4. That
variability is UTF-8's great strength — plain ASCII stays one byte — but it means byte
length is not something you can eyeball from the text.
Put it together and a single string has up to four different "lengths": its UTF-8
byte count, its UTF-16 code-unit count (JavaScript's
.length), its code-point count, and the number of
grapheme clusters a human would count. For "a😀" those are 5 bytes, 3
code units, 2 code points, and 2 graphemes. Whenever a length limit, a progress bar, or a
database column feels off by a bit, it is almost always because two of these four numbers
were assumed to be equal.
Frequently Asked Questions
Why does "😀".length return 2 in JavaScript?
Because String.length counts UTF-16 code units, not characters. The emoji
is above U+FFFF, so UTF-16 stores it as a surrogate pair — two 16-bit
units — and reports a length of 2. Walk the string with for...of,
[...str], or Array.from(str) to count code points, where it
is 1.
What is the difference between a code point and a grapheme cluster?
A code point is a single Unicode scalar value, like U+0301 (a combining
accent). A grapheme cluster is what a person sees as one character, which can be
several code points combined — e plus U+0301 renders as one
é, and many emoji are several joined code points. Users count graphemes;
code rarely does by default.
Why do two identical-looking strings compare as unequal?
Almost always Unicode normalization. The same visible text can be encoded as
precomposed (NFC) or decomposed (NFD) code points — é as
U+00E9 versus e + U+0301 — which are different
byte sequences. Call str.normalize('NFC') on both sides before comparing,
hashing, or de-duplicating.
How do I count characters the way a human sees them?
Use grapheme segmentation, not .length. In modern JavaScript,
Intl.Segmenter with granularity 'grapheme' walks the string
by user-perceived characters, so a flag or a combined emoji counts as one. Code-unit
and code-point counts will both over-count such cases.
How many bytes does one character take in UTF-8?
One to four, depending on the character. ASCII is 1 byte, most Latin, Greek, and
Cyrillic letters are 2, most of the Basic Multilingual Plane including common CJK is 3,
and emoji and other astral characters are 4. That is why a string's byte length,
code-unit count, and code-point count are often three different numbers.
What is a surrogate pair, and why does slicing break emoji?
Characters above U+FFFF are stored in UTF-16 as two units — a high
surrogate (U+D800–U+DBFF) and a low surrogate
(U+DC00–U+DFFF) — that are only valid together. Slicing or indexing by
code-unit position can land between them, leaving a lone surrogate that is invalid and
shows as �. Split by code point or grapheme to keep characters intact.