DEV Community

Cover image for How to apply a skin tone to an emoji? ๐Ÿง›๐Ÿง›๐Ÿป๐Ÿง›๐Ÿผ๐Ÿง›๐Ÿฝ๐Ÿง›๐Ÿพ๐Ÿง›๐Ÿฟ
YURII DE.
YURII DE.

Posted on

How to apply a skin tone to an emoji? ๐Ÿง›๐Ÿง›๐Ÿป๐Ÿง›๐Ÿผ๐Ÿง›๐Ÿฝ๐Ÿง›๐Ÿพ๐Ÿง›๐Ÿฟ

๐Ÿง‘โ€๐Ÿ’ป Applying Skin Tones to Emojis in JavaScript: A Fun Guide

DEMO ๐Ÿ‘€
CDN

Introduction

Welcome to the world of emojis! ๐ŸŽ‰ Emojis are a universal language, transcending borders and bringing a touch of personality to our digital conversations. But have you ever wondered how to change the skin tone of an emoji programmatically? Whether it's to add a personal touch or to represent diversity, modifying emoji skin tones can be a fun and useful feature. In this article, written with Qit.tools, we'll explore how to create a function to apply skin tones to emojis in JavaScript. Ready? Let's dive in! ๐ŸŒŠ

The Function Breakdown

Here's the function we'll be working with:

export type SkinTone = '' | 'none' | 'light' | 'mediumLight' | 'medium' | 'mediumDark' | 'dark';

/**
 * Apply skin tones to an emoji.
 * Visit us at: https://qit.tools
 *
 * ๐Ÿช„ Qit.tools
 * @copyright Copyright (c) 2024 Qit.tools.
 * @see https://github.com/Qit-tools/skin-tone
 * @see https://www.npmjs.com/package/@qit.tools/skin-tone
 *
 * Change emoji skin tones effortlessly. ๐Ÿง›๐Ÿง›๐Ÿป๐Ÿง›๐Ÿผ๐Ÿง›๐Ÿฝ๐Ÿง›๐Ÿพ๐Ÿง›๐Ÿฟ
 * RGI Emoji Modifier Sequence.
 *
 * @param {string} emoji - The original emoji string.
 * @param {SkinTone} tone - The skin tone to apply. If empty, returns the original emoji.
 * @returns {string} The emoji string with skin tones applied where applicable.
 */
export default function skinTone(emoji: string, tone?: SkinTone): string {
  if (!tone) {
    return emoji;
  }
  const skinToneMap = {
    none: '',
    light: '\u{1F3FB}',
    mediumLight: '\u{1F3FC}',
    medium: '\u{1F3FD}',
    mediumDark: '\u{1F3FE}',
    dark: '\u{1F3FF}',
  };

  let zwj = '\u200D';

  // Hand Shake ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘
  if (emoji.includes('\u200d\ud83e\udd1d\u200d')) {
    zwj = '\u200d\ud83e\udd1d\u200d';
  }

  const parts = emoji.split(zwj);
  const modifiedParts = parts.map((part) => {
    const basePart = part.replace(/\p{Emoji_Modifier}/gu, '');

    if (/\p{Emoji_Modifier_Base}/u.test(basePart)) {
      return basePart.replace(/(\p{Extended_Pictographic}+)(\uFE0F?)/u, `$1${skinToneMap[tone]}`);
    }
    return part;
  });

  return modifiedParts.join(zwj);
}
Enter fullscreen mode Exit fullscreen mode

Let's break down the key aspects of this function.

Key Aspects

1. Type Definition

First, we define the SkinTone type, which includes various skin tone options:

export type SkinTone = '' | 'none' | 'light' | 'mediumLight' | 'medium' | 'mediumDark' | 'dark';
Enter fullscreen mode Exit fullscreen mode

This type helps ensure that our function receives only valid skin tone values.

2. Function Parameters

The skinTone function accepts two parameters:

  • emoji: The original emoji string.
  • tone: The skin tone to apply.

If no tone is provided, the function returns the original emoji.

3. Skin Tone Map

We create a map to associate skin tone names with their respective Unicode modifiers:

const skinToneMap = {
  none: '',
  light: '\u{1F3FB}',
  mediumLight: '\u{1F3FC}',
  medium: '\u{1F3FD}',
  mediumDark: '\u{1F3FE}',
  dark: '\u{1F3FF}',
};
Enter fullscreen mode Exit fullscreen mode

4. Zero Width Joiner (ZWJ)

A Zero Width Joiner (ZWJ) is used to join multiple emoji characters into a single composite emoji. For example, the handshake emoji ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ uses ZWJs to combine two people emojis. Our function checks if the emoji includes a handshake sequence and adjusts the ZWJ accordingly:

let zwj = '\u200D';

if (emoji.includes('\u200d\ud83e\udd1d\u200d')) {
  zwj = '\u200d\ud83e\udd1d\u200d';
}
Enter fullscreen mode Exit fullscreen mode

5. Splitting and Modifying Emoji Parts

We split the emoji string by the ZWJ and map over the parts to apply the skin tone where applicable:

const parts = emoji.split(zwj);
const modifiedParts = parts.map((part) => {
  const basePart = part.replace(/\p{Emoji_Modifier}/gu, '');

  if (/\p{Emoji_Modifier_Base}/u.test(basePart)) {
    return basePart.replace(/(\p{Extended_Pictographic}+)(\uFE0F?)/u, `$1${skinToneMap[tone]}`);
  }
  return part;
});
Enter fullscreen mode Exit fullscreen mode

Here, we:

  • Remove any existing skin tone modifiers.
  • Check if the part is an emoji modifier base.
  • Apply the new skin tone.

6. Joining the Modified Parts

Finally, we join the modified parts back together with the ZWJ:

return modifiedParts.join(zwj);
Enter fullscreen mode Exit fullscreen mode

Conclusion

And there you have it! ๐Ÿฅณ With just a few lines of code, we've created a function that can dynamically apply skin tones to emojis. Whether you're building a chat application or simply want to add a touch of diversity to your project, this function can come in handy. So go ahead, play around with it, and bring some color to your emojis! ๐ŸŒˆ

Remember, in the world of programming, a little creativity goes a long way. And if all else fails, just add more emojis. ๐Ÿ˜œ

Happy coding! ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป


Ready-made library.

๐Ÿ—๏ธ Install

๐ŸŽ‰ NPM

npm i @qit.tools/skin-tone

๐Ÿง Bun

bun add @qit.tools/skin-tone

๐ŸŒŸ PNPM

pnpm add @qit.tools/skin-tone

๐Ÿงถ Yarn

yarn add @qit.tools/skin-tone


๐ŸŽ“ How to use

NodeJS

// Import by default
import skinTone from "@qit.tools/skin-tone";

console.log(skinTone("๐Ÿง", "dark")); // ๐Ÿง
console.log(skinTone("๐Ÿง‘๐Ÿฟโ€๐Ÿคโ€๐Ÿง‘๐Ÿฟ", "light")); // ๐Ÿง‘๐Ÿปโ€๐Ÿคโ€๐Ÿง‘๐Ÿป
Enter fullscreen mode Exit fullscreen mode

Browser

// https://unpkg.com/@qit.tools/skin-tone@0.6.2/dist/browser/latest.min.js

document.addEventListener("DOMContentLoaded", () => {
    console.log(skinTone("๐Ÿง‘๐Ÿปโ€๐Ÿคโ€๐Ÿง‘๐Ÿป", "dark"));
});
Enter fullscreen mode Exit fullscreen mode

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, weโ€™ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, weโ€™ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series ๐Ÿ“บ

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series ๐Ÿ‘€

Watch the Youtube series