Changing Emoji Skin Tones Programmatically
Tags: javascript, css, webdev, emoji
Published: 2020-10-03 19:30:16

So, you know how many emoji have different skin tones? Emoji skin tones are extremely popular, especially over text and on social media. The raised black fist emoji (✊🏿) was voted [“The Most 2020 Emoji”](https://worldemojiawards.com/2020/most-2020-emoji) by Emojipedia’s World Emoji Awards.

Each tone is a modifier and many emoji are made up of modifiers and base encodings that map to specific characters. Unfortunately, not every emoji library supports modifiers. But, given their popularity, emoji skin tone modifiers are more than a “nice to have” feature. Plus, they’re a smart way to work because they allow us to write more modular and efficient code.

So that’s what we’re doing in this article: figure out how to work with emoji modifiers programmatically. This way, if you’re ever stuck without skin tone support — or want to create custom variations of other emoji — then you’ll know how!

## Meet the Fitzpatrick scale

Skin tone modifiers were officially added to emoji in 2015 as part of [Unicode 8.0](https://unicode.org/versions/Unicode8.0.0/). They are based on the [Fitzpatrick scale](https://en.wikipedia.org/wiki/Fitzpatrick_scale), which is a formal classification of human skin tones. The following chart shows how the emoji characters match to Fitzpatrick types:

| Skin tone character | Fitzptrick type |
|---------------------|-----------------|
| 🏻                   | 1-2             |
| 🏼                   | 3               |
| 🏽                   | 4               |
| 🏾                   | 5               |
| 🏿                   | 6               |

In the simplest use case, when one of these characters is appended to an emoji that supports skin tone modifiers, it will change the skin tone of the emoji.

Another way to say that: 👶 +🏽 = 👶🏽

## Applying skin tone modifiers with CSS

To swap between emoji skin tones using CSS, we would start with the base emoji character (👶) and then append the skin tone using the `::after` pseudo-selector.

{% codepen https://codepen.io/brew-install-buzzwords/pen/dyMOqjK %}

In addition to using the rendered emoji characters, we could use the Unicode hex codes instead:

{% codepen https://codepen.io/brew-install-buzzwords/pen/XWdNxWz %}

## Removing and swapping skin tone modifiers with JavaScript

What if the emoji you’re working with has already had a skin tone modifier applied? For that, we’ll need to move beyond CSS. Here’s an example using JavaScript:

{% codepen https://codepen.io/brew-install-buzzwords/pen/PoNbxge %}

What’s going on here? First, we start with a baby emoji with Fitzpatrick Type 4. We then pass it into the function removeModifier, which searches for any of the skin tone modifiers and removes it from the string. Now that we have the emoji without a modifier, we can add whichever modifier we like.

While this approach works with many emoji, we run into problems when other modifiers are introduced. That’s why we now need to talk about…

## Working with ZWJ sequences

[Zero width joiner (ZWJ) sequences](https://unicode.org/emoji/charts/emoji-zwj-sequences.html) are like the compound words of Unicode. They consist of two or more emoji joined by the zero width joiner, `U+200D`.

ZWJ sequences are most commonly used to add gender modifiers to emoji. For example, a person lifting weights, plus ZWJ, plus the female sign, equals a woman lifting weights (️🏋️ + ♀︎ = 🏋️‍♀️).

There’s a few important things to need to keep in mind when working with ZWJ sequences:

* The sequences are [only recommendations](https://unicode.org/emoji/charts/emoji-zwj-sequences.html). They come from the [Unicode Consortium](https://home.unicode.org/) and are not guaranteed to be supported on every platform. If they are not supported by a platform, then a fallback sequence of regular emoji will be displayed instead.
* Skin tone modifiers, if present, must be included after the emoji but before the ZWJ.
* Some ZWJ sequences include multiple emoji that each have different skin tone modifiers.

Given this information, we need to make the following changes to the previous code example:

* The skin tone modifiers need to be inserted immediately after any base emoji rather than simply being appended to the end of the emoji.
* If there are multiple emoji in a ZWJ sequence that have skin tone modifiers, then the modifiers will need to be replaced for each of those emoji.

{% codepen https://codepen.io/brew-install-buzzwords/pen/QWNOGRz %}

## Limitations

From this example, you may notice the limitation of consistency. The editor view shows each of the characters in a ZWJ sequence separately, with exception to the skin tone modifiers, which are immediately applied to their corresponding emoji. The console or results views, on the other hand, will attempt render the character for the entire sequence.

Support for this will vary by platform. Some editors may attempt to render ZWJ sequences, and not all browsers will support the same sets of ZWJ sequences.

Additionally, adding skin tones in a ZWJ sequence requires knowing what’s being used as the base emoji. While this would be relatively simple in a situation where the emoji are provided by a known collection, things become more difficult if we want to be able to handle arbitrary input from a user.

Also, be aware that the CSS solutions in this post are not compatible with ZWJ sequences.

## Questions to guide development

I put some questions together you may want to ask yourself when you’re designing a system that needs to handle emoji skin tone modifiers:

* Do I have control over which emoji my system will interact with?
* Does my emoji library have information about which emoji support skin tone modifiers?
* Does my system need to add, remove, or change the modifiers?
* Does my platform support ZWJ sequences? If so, which ones?
* Does my system need to support ZWJ sequences with [multiple skin tone modifiers](https://unicode.org/emoji/charts/emoji-zwj-sequences.html#1f9d1_1f3fc_200d_1f91d_200d_1f9d1_1f3fd)?

Hopefully, between the answers to these questions and the examples we’ve looked at here, you’ll have everything you need to support emoji skin tone modifiers in situations where you need them.

## More

If you liked this, consider [subscribing to my newsletter](https://mailchi.mp/89dc077154c7/brewinstallbuzzwords) or reading one of my other posts:

* [5 tips for publishing your first npm package](https://dev.to/brewinstallbuzzwords/5-tips-for-publishing-your-first-npm-package-3e4a)
* [4 Hugo Beginner Mistakes](https://dev.to/brewinstallbuzzwords/4-hugo-beginner-mistakes-90h)
* [Introducing meme-type: A translator for internet speak](https://dev.to/brewinstallbuzzwords/introducing-meme-type-a-translator-for-internet-speak-i6a)