Cadey is coffee
<Cadey> Hello! Thank you for visiting my website. You seem to be using an ad-blocker. I understand why you do this, but I'd really appreciate if it you would turn it off for my website. These ads help pay for running the website and are done by Ethical Ads. I do not receive detailed analytics on the ads and from what I understand neither does Ethical Ads. If you don't want to disable your ad blocker, please consider donating on Patreon or sending some extra cash to xeiaso.eth or 0xeA223Ca8968Ca59e0Bc79Ba331c2F6f636A3fB82. It helps fund the website's hosting bills and pay for the expensive technical editor that I use for my longer articles. Thanks and be well!

The GraphicalEmoji hack

Read time in minutes: 3

Today, I tried to write a JSX component that included an emoji in it. Specifically this emoji: ⚠️.

This emoji is special because there's actually two forms of it:

  • ⚠︎ (the textual form)
  • ⚠️ (the graphical form)

EDIT: Apparently this difference isn't showing up on every browser engine the same way. Please trust me that there is a difference, one of them on my MacBook running Microsoft Edge is a text-only emoji that has no color in it. This is why I was so confused, scared, and on the verge of tears after being gaslit by my browser. God is dead because font rendering killed him.

When I was making this component, I wanted the graphical form of it. The following things did not work:

  • Adding the explicit "make this graphical" Unicode instruction: \u{FE0F}
  • Declaring the emoji as the string "\u{26A0}\u{FE0F}" and then using it as a variable: <span>{warningEmoji}</span>
  • Using the variable in a format string: <span>{`${warningEmoji}`}</span>

Turns out, this is actually a fairly widespread problem with fonts that have the textual form of emoji defined but not the graphical form of it defined. The font my blog uses is one of them, so to get the graphical ⚠️ I've been using above, I had to paste this HTML snippet:

<span style="font-family: Times New Roman">⚠️</span>

Aoi is facepalm
<Aoi> Oh god. Really? That is so, so cursed.

Yes, really. In order to make the emoji render correctly, I had to instruct the browser to render it in Times New Roman because that does not have the emoji defined. It will then fall back to the system font, giving us the ⚠️ that we truly desire.

Here is the JSX component I had to write:

export interface GraphicalEmojiProps {
  emoji: string;
}

/** Listen to me for my tale of woe:
 * Fonts are complicated. Fun fact: fonts are actually Turing-complete programs
 * that run in browsers. Yes, font rendering is really that complicated. This
 * component is a dirty, ugly, disgusting HACK that works around font
 * rendering in order to forcibly display the graphical form of an emoji.
 *
 * This works because times new roman always displays the graphical forms of
 * emoji. No, I don't know why either. It slightly scares me.
 *
 * Either way, this works and I'm not brave enough to question why.
 */
export default function GraphicalEmoji({ emoji }: GraphicalEmojiProps) {
  return <span style={{ fontFamily: 'Times New Roman' }}>{emoji}</span>;
}

This code is free as in mattress. If you decide to use it, it's your problem.

Cadey is coffee
<Cadey> I hate fonts.


This article was posted on M03 08 2023. Facts and circumstances may have changed since publication. Please contact me before jumping to conclusions if something seems wrong or unclear.

Tags: cursed JavaScript JSX fontRendering dearGodHelpMe

The art for Mara was drawn by Selicre.

The art for Cadey was drawn by ArtZora Studios.

Some of the art for Aoi was drawn by @Sandra_Thomas01.