A single emoji on screen is often three, five or seven code points glued together. Paste one below to see each piece, the job each piece does, and the exact escape your code, HTML or database expects. Paste codes instead and you get the emoji back.
Seven building blocks explain almost every multi-part emoji you will meet.
Unicode gives each base emoji one code point. Everything beyond the base, a skin tone, a gender, a second person, a flag, gets built by stacking extra code points behind the base. Your phone or browser reads the stack and draws one picture. If the font has no picture for the stack, you see the parts in a row instead.
| Building block | Code points | Job | Example |
|---|---|---|---|
| Zero width joiner | U+200D | Glues the emoji on either side into one picture. | 👨👩👧 |
| Variation selector 16 | U+FE0F | Asks for the color emoji form of a symbol older than emoji. | ❤️ |
| Skin tone modifier | U+1F3FB to U+1F3FF | Five tones based on the Fitzpatrick scale, placed right after a person or hand. | 👋🏼 |
| Regional indicator | U+1F1E6 to U+1F1FF | Letters A to Z. Two in a row spell an ISO country code, drawn as a flag. | 🇵🇰 |
| Combining keycap | U+20E3 | Draws a key outline around a digit, # or *, after U+FE0F. | 1️⃣ |
| Tag characters | U+E0020 to U+E007F | Spell a region code such as gbeng after a black flag. Only England, Scotland and Wales are on the recommended list. | 🏴 |
| Hair component | U+1F9B0 to U+1F9B3 | Red, curly, bald or white hair, joined to a person with U+200D. | 👩🦰 |
The breakdown cards in the converter color each piece by its job, using the key above the cards. Load sample fills the box with a short line holding seven different cases. The 👩🏽💻 card lists four code points: U+1F469 woman, U+1F3FD medium skin tone, U+200D joiner, U+1F4BB laptop. Delete the joiner and most systems draw two separate emoji, a woman and a laptop.
The England flag on the same line is the heaviest case: seven code points, 28 bytes, for one small flag.
Each language counts a different unit, so the same string reports a different size.
| Check | Counts | 😀 | ❤️ | 👨👩👧 | England flag |
|---|---|---|---|---|---|
str.length in JavaScript, s.length() in Java | UTF-16 code units | 2 | 2 | 8 | 14 |
len(s) in Python, CHAR_LENGTH() in MySQL | Code points | 1 | 2 | 5 | 7 |
len(s) in Go, LENGTH() in MySQL | UTF-8 bytes | 4 | 6 | 18 | 28 |
s.count in Swift, Intl.Segmenter in JavaScript | Visible characters | 1 | 1 | 1 | 1 |
The stats strip under the converter shows all four counts for whatever you paste. Three places where the gap bites:
Browsers measure maxlength in UTF-16 units. A field set to maxlength="10" accepts only five 😀, and one family emoji uses eight of the ten slots.
MySQL sizes VARCHAR(n) in code points. A column of VARCHAR(20) holds twenty plain smileys but only four family emoji. The older utf8 charset (an alias for utf8mb3) stores at most 3 bytes per character, so every emoji above U+FFFF fails with Incorrect string value: '\xF0\x9F\x98\x80'. Use utf8mb4 for the column, the table and the connection.
Cutting a string with substring(0, n) in JavaScript or Java splits surrogate pairs and leaves a broken half. Cut on visible characters with Intl.Segmenter instead.
Same emoji, nine spellings. The output format menu writes each of them.
| Where the text goes | Menu option | Grinning face written out |
|---|---|---|
| JavaScript (ES2015 and later), PHP 7+, Ruby, Swift, Rust | \u{} escape | \u{1F600} |
| JSON, Java, pre-2015 JavaScript | UTF-16 \uXXXX | \uD83D\uDE00 |
| Python, C#, C and C++, Go | \U0001F600 | \U0001F600 |
| HTML page or attribute | HTML hex or decimal entity | 😀 or 😀 |
CSS content property | CSS escape | \01F600 |
| URL query string | Percent-encoded | %F0%9F%98%80 |
| Hex dump, packet capture | UTF-8 bytes | F0 9F 98 80 |
| Docs, bug reports, specs | U+ notation | U+1F600 |
The highlighted JSON row trips people up most. JSON has no \u{1F600} form, and strict parsers throw an error. Write the surrogate pair, or skip escaping and save the raw emoji, since JSON files are UTF-8 by default. PHP's json_encode writes the surrogate pair unless you pass JSON_UNESCAPED_UNICODE.
The CSS escape is padded to six digits on purpose. A shorter \1F600 followed by a letter from a to f would swallow the letter as part of the number.
With Leave letters and digits readable ticked, a line like Hi 😀 becomes Hi \u{1F600}, ready to drop into a string literal. Quotes, backslashes and angle brackets get escaped either way, so the output never closes your string or tag early.
Match the symptom on your screen to the cause. Paste the broken text into the converter to confirm.
😀 (F0 9F 98 80) got read as Windows-1252, one letter per byte. The data is fine. The reader picked the wrong encoding. Send Content-Type: text/html; charset=utf-8, or reopen the file as UTF-8.utf8mb4 and run SET NAMES utf8mb4 on the connection. Text already saved as question marks stays lost.U+200D joiners. Paste the text in and check the card. No joiner in the chain points to a sanitizer or an old storage layer.U+FE0F, so some apps draw the text form. Add U+FE0F after U+2764 to request the red emoji.\uD83D in red with a short reason.Know these before you trust a result in production.
2764 FE0F decodes to a heart. A run of two-digit values such as F0 9F 98 80 decodes as UTF-8 bytes only when the run forms valid UTF-8. Prefix bytes with \x or % to remove doubt. Spaces between U+ codes or bare hex count as separators, so write U+0020 for a real space. Spaces between escapes such as \u{1F600} stay in the result.Short answers to the questions developers send us most about emoji encoding.
The red heart is two code points: U+2764 (heavy black heart) followed by U+FE0F, the emoji style selector. Without U+FE0F some apps draw a black text heart. In HTML write ❤️ and in JavaScript write \u{2764}\u{FE0F}.
JavaScript strings count UTF-16 code units. Any emoji above U+FFFF needs a surrogate pair, which is two units. Use [...str].length to count code points, or Intl.Segmenter to count visible characters.
Write the UTF-16 surrogate pair, for example \uD83D\uDE00 for the grinning face. JSON has no \u{1F600} syntax. Saving the raw emoji in a UTF-8 file also works with every standard JSON parser.
The column, table or connection uses a charset limited to 3 bytes per character, such as utf8 (utf8mb3) in MySQL. Most emoji need 4 bytes. Switch all three to utf8mb4 and re-save the text, since the question marks replaced the original data.
A country flag is two regional indicator letters, such as P and K for Pakistan. The Windows emoji font has no flag pictures, so Windows prints the letters. The text itself is correct and shows a flag on Android, iOS and macOS.
No. Encoding and decoding run in your browser. The only time your text leaves the page is when you press Copy link, which puts the text in the URL you share.