Emoji Skin Tones: Manipulating Modifiers in Code
Emoji skin tone modifiers — five tones based on the Fitzpatrick scale of human skin types — have been part of the Unicode standard since Unicode 8.0, released in 2015. Each tone is represented by its own Unicode character (e.g., U+1F3FE for medium-dark skin), and applying one is as simple as appending it to a base emoji character: 👶 + 🏽 = 👶🏽.
Many emoji libraries assume they’ll never need to handle modifiers, or handle them poorly. But given how widely they’re used, it’s worth knowing how to add, strip, and swap these tones yourself, using both CSS and JavaScript.
| Skin tone character | Fitzpatrick type |
|---|---|
| 🏻 | 1-2 |
| 🏼 | 3 |
| 🏽 | 4 |
| 🏾 | 5 |
| 🏿 | 6 |
Adding a tone with CSS
To skin-tone an emoji purely with CSS, start with the base emoji and append the tone character via the ::after pseudo-selector. The base emoji and the modifier will render as a single combined character in supporting browsers.
The same approach works if you substitute the modifier’s Unicode hex codepoint for the literal emoji character.
Removing and swapping tones with JavaScript
When you don’t know whether an emoji already carries a tone, CSS is no longer enough. In JavaScript you can write a simple helper that strips any existing skin tone modifier from the emoji string, then append the desired tone character:
- Iterate through the emoji string looking for one of the five Fitzpatrick modifier characters.
- Remove the modifier from the string, leaving the bare base emoji.
- Append the new modifier character.
That works fine for single-character emoji, but falls apart once you introduce other kinds of modifiers, particularly in ZWJ sequences.
Handling ZWJ sequences
Zero width joiner (ZWJ) sequences are Unicode’s way of constructing compound emoji from multiple parts. Two or more emoji are joined by the ZWJ character U+200D. The most common examples are gender-modified emoji: 🏋️ + U+200D + ♀︎ = 🏋️♀️.
Working with ZWJ sequences adds three important constraints:
- The Unicode Consortium’s ZWJ sequences are recommendations, not guarantees — unsupported platforms fall back to a sequence of unrelated base emoji.
- A skin tone modifier must be attached to its own base emoji and comes before the ZWJ that connects them, not at the end of the whole string.
- An emoji with multiple people can carry several skin tones, one per person in the sequence.
For the JavaScript approach, that means the modifier-removal function must:
- Insert each modifier immediately after its corresponding base emoji, rather than at the tail of the string.
- Detect and process every emoji in the ZWJ sequence that may have a skin tone, not just the first.
Known limitations
There are important edge cases to be aware of. Many code editors render each character of a ZWJ sequence separately, while a browser console will apply the modifier only to the immediately preceding emoji and render the rest of the sequence as-is. Support for rendering ZWJ sequences at all varies wildly by editor, browser, and platform.
Another catch: applying a tone mid-sequence reliably requires knowing which codepoints form the base emoji. That’s easy for a controlled collection of emoji but painful for arbitrary user input. And none of the CSS-based techniques described above work reliably on ZWJ sequences.
Design questions worth asking first
Before you build a modifier-handling system, decide what your scope actually is:
- Do you know which emoji your system will need to handle?
- Does your emoji library expose whether a given emoji supports skin tone modifiers?
- Will the system only apply tones from scratch, or also need to strip or swap existing ones?
- Does the target platform support any ZWJ sequences? If so, which ones?
- Do you need to handle ZWJ sequences with more than one modified person in them?
With those questions answered, the techniques above cover everything needed to add, remove, or change emoji skin tones in your own applications.



