Custom yellow handshake emojis with zero-width joiners

Apple added support for multi-skin tone handshake emojis in 2022, allowing you to go from the old standby of 🀝 to supporting handshakes like πŸ«±πŸ»β€πŸ«²πŸΏ. However while these handshake emojis look similar, they're actually substantially different.

How this works

Each character (and therefore each emoji) is made up of Unicode codepoints. We can look at the codepoints that make up an emoji using this JavaScript code.

[...'🀝'].map(c => 'U+' + c.codePointAt(0).toString(16)).join(' ')
🀝
U+1F91D
πŸ«±πŸ»β€πŸ«²πŸΏ
U+1FAF1 U+1F3FB U+200D U+1FAF2 U+1F3FF

From this we can see that the yellow handshake is only one codepoint, because it was originally just a normal emoji. The modified color handshake however is actually a composite, composed of five different characters: 1 The color modifier names comes from the Fitzpatrick scale, a human skin color phenotypal scale created by an American dermatologist in the 1970s β€” and a scale that is often critiqued for its eurocentric bias.

The ZWJ character is the real star of the show, gluing together disparate emojis into something that Apple and other sites can either choose or not choose to render as a single grapheme (and also backs emojis like πŸ‡ΊπŸ‡³ 2 The flags lead to one of my favorite JS behavior, where inane strings like replacing the emoji flag of Sri Lanka with Dominica in Albania-Kyrgyzstan helpfully yields Andorra-Madagascar (because swapping LK for DM in AL KG becomes AD MG. or πŸ‘©β€β€οΈβ€πŸ’‹β€πŸ‘¨).

Novel ones

However this also allows us to create emojis that Apple's UI doesn't naturally allow us to create. The UI allows us to pick either the uniformly yellow emoji, or build a hand of two colors. But what if we want yellow and black instead of white and black?

Easy! Instead of taking the five characters and modifying them both with colors we can only modify one of them. 3 Or none of them, creating πŸ«±β€πŸ«², which is visually identical to 🀝 and yet composed of three codepoints instead of one. We can then build it back into a character with JavaScript, allowing us to create two emoji that Apple's UI doesn't explicitly support (even though their rendering does). 4 Though unfortunately these emojis don't render as large single messages on iOS/macOS. I'm not sure why β€”Β a mystery for future me!

console.log('\u{1FAF1}\u{200D}\u{1FAF2}\u{1F3FF}')
πŸ«±β€πŸ«²πŸΏ
U+1FAF1 U+200D U+1FAF2 U+1F3FF
πŸ«±πŸΏβ€πŸ«²
U+1FAF1 U+1F3FF U+200D U+1FAF2

  1. The color modifier names comes from the Fitzpatrick scale, a human skin color phenotypal scale created by an American dermatologist in the 1970s β€” and a scale that is often critiqued for its eurocentric bias. ↩︎

  2. The flags lead to one of my favorite JS behavior, where inane strings like replacing the emoji flag of Sri Lanka with Dominica in Albania-Kyrgyzstan helpfully yields Andorra-Madagascar (because swapping LK for DM in AL KG becomes AD MG.  ↩︎

  3. Or none of them, creating πŸ«±β€πŸ«², which is visually identical to 🀝 and yet composed of three codepoints instead of one. ↩︎

  4. Though unfortunately these emojis don't render as large single messages on iOS/macOS. I'm not sure why β€”Β a mystery for future me! ↩︎