Font Awesome

What We Learned About Painting Ourselves into a Corner with Our Own Tech: Icon Unicodes and Ligatures Edition

by Mike Wilkerson

You must unlearn what you have learned

In this blog, we’ll outline some of the key challenges that emerged with unicodes, and how we found solutions. Well cover: 

  • Using standard unicode values for some English alphabet characters.
  • Keeping our own Private Use Area unicodes for reliability with ligatures, while also having unicode aliases for emoji compatibility.
  • Associating multiple glyphs with a single icon name and unicode. 

If you use Font Awesome Duotone OTF fonts in Desktop apps, or CSS pseudo-elements with Duotone Webfonts, big changes are coming for you in Font Awesome 6.

Even if you don’t use Font Awesome in these ways, this peek under the hood will reveal some of the ways we’re working on our tech to prepare for adding lots more Awesome to come.

A Primer on Unicodes in Font Awesome 5 

What’s a unicode? 

First things first. A unicode is just a numeric value that represents a character. It’s often written in hexadecimal, but it doesn’t matter what notation is used: it’s the same value regardless.

For example in Font Awesome 5: take our beer icon:

The unicode for that icon is “f0fc.” That’s just the hexadecimal (base 16) representation of a number. The decimal notation (base 10) is “61692.”

What Are Glyphs? 

A glyph is basically a little picture. It kinda works like an SVG (a vector image). But in the context of a font, it’s called a glyph.

Duotone Icons Use Multiple Glyphs

This single icon, the beer icon in the Duotone style, entails two different glyphs, each referenced by a separate unicode. So it’s really two different characters, as far as the font is concerned.

This single icon, the beer icon in the Duotone style, entails two different glyphs, each referenced by a separate unicode. So it’s really two different characters, as far as the font is concerned. 

To bring the two together into a single icon, our Webfont CSS overlays them. In a Desktop app, using our Desktop OTF fonts, it’s up to you to overlay and align these two glyphs to make it look like a single icon.

Notice that the unicode for beer’s primary glyph is still f0fc, and the unicode for its secondary glyph is 10f0fc. In Font Awesome 5, that’s how we assigned secondary unicodes for our Duotone icons: “put a 10 in front”. Likewise, coffee’s unicode was f0f4, so the unicode for its Duotone secondary glyph was 10f0f4.

Simple and memorable. But it painted us into a corner.

Problems We Faced Building Font Awesome 6

There were two key places where “put a 10 in front” caused a problem.

We added icons for all of the numeric digit and English alphabet characters: 0-9, a-z, A-Z. And lots of punctuation characters. We wanted those to be in Duotone as well, and we wanted to assign the standard unicode code points to them. 

When you type a capital “A” on your QWERTY keyboard, it emits data corresponding to the unicode point U+0041. So we wanted the unicode for our “A” icon to be “41”.

Now, “put a 10 in front,” to make the secondary unicode for A’s Duotone secondary glyph. That’s U+1041. But that unicode point is already taken by MYANMAR DIGIT ONE. D’oh!

You see, in Font Awesome 5 we only used unicodes for our icons that were in one of the Private Use Areas, the regions of the unicode number space that are not already reserved for standard characters in various languages. As long as we stayed in one of those lanes with our primary unicode assignments, “put a 10 in front” happened to work out fine for a secondary unicode assignment. But not for these standard characters like the English letter “A”.

And then there were the emoji characters. For Font Awesome 6, we wanted to get more emoji. We already have lots of icons that correspond to standard emojis, and we’re adding a whole bunch more. We want those emojis to be addressable in our fonts using their standard unicode values.

What could be more classic than a smiley emoji?

Here’s the Font Awesome 5 “grin” icon with unicode f580.

In Font Awesome 6, it’s been renamed as “face-grin”. This makes its name more consistent with many other face-related emoji icons in FA6. Of course, in FA6, there’s a name alias for FA5 compatibility. So if you were using the CSS class “fa-grin” to get that icon in FA5, it’ll still work in FA6, just as if you’d used the CSS class “fa-face-grin”.

Now, what if you’ve got a slide presentation with that smiley emoji in it, and you want to use Font Awesome icons for your emojis? Wouldn’t it be great if it just worked?

The standard unicode for that emoji is U+1F600.

(Can you feel your back against the wall yet?)

So what if we assigned “1f600” as the Font Awesome unicode value for the primary glyph of that face-grin icon? What would the secondary unicode be? Put a 10 in front, and you get “101f600”. 

But guess what? That’s not a valid unicode value. The highest valid Private Use Area unicode is 10fffd. It’s got to fit into a 24-bit number. You can’t store hexadecimal 101f600 in 24-bits; it’s too big!

Here’s what you’ll find in the Icon Gallery for face-grin in Font Awesome 6-beta2:

Notice that we still have f580 as the primary unicode. But there’s no secondary unicode like 10f580. Instead, you see “f580\f580”. And if you were to copy the “secondary glyph” (the darker tiny version of the icon on the top right) and paste it into a plain text document, you might be surprised to see: “face-grin##”? Do the same for the primary glyph and you’ll see “face-grin#”. What?

Solution 1: Ligatures 

So, if we need to refer to multiple glyph layers for a single icon, and the secondary unicode schema (“put a 10 in front”) has broken down, how do we do it?


In FA6, Duotone icons will have just one unicode, but they’ll still have multiple glyphs that can be styled independently of each other. Those glyphs can be referenced using ligatures. For the Desktop OTFs, the ligatures are easy to type, based on the icon’s name. In the Webfont CSS, they’re really short — two characters long! — to keep the byte size down.

This may initially confuse those who have internalized the “put a 10 in front” FA5 paradigm, where there was a separate unicode value for each glyph of a Duotone icon. But give it a chance, I think you may come to appreciate the new possibilities this opens for us, starting by getting us out of that corner.

What’s a Ligature?

A ligature is basically just a unicode sequence that the font knows how to resolve into something else. Different kinds of ligatures do different things, but the basic kind of ligature I’m talking about now is a substitution ligature. Simply, a single glyph is substituted for some sequence of characters.

Yes, yes, to the font nerds out there, I’ll admit: technically, at the implementation level, a substitution ligature substitutes a single glyph for a sequence of glyphs. But just roll with me here: when you actually use it in a document, it’s a sequence of unicode characters (each of which is mapped to a glyph, and then yes, it’s a sequence of glyphs from there).

For example, if I’m using the new Font Awesome 6 Desktop OTF font in Illustrator, and I type “beer-mug-empty”, that ligature will be magically replaced by this:

Wait! What? That’s the whole Duotone icon — both the primary and secondary glyphs? you may be thinking.

No, this is a different part of the Awesome in Font Awesome 6. That there is a single SVG glyph. It only works in apps that support SVG fonts, but it sure is handy when available. So, no more having to work with each separate glyph if all you want is just that basic, composite Duotone icon with its default styling.

Unfortunately, even in apps that support SVG fonts, they tend not to support styling those SVG glyphs. So if you want a purple beer mug, you’ll still need to reference each separate glyph layer, style them individually, and align them yourself.

Wanna guess what you get when you go to the Font Awesome 6 (Beta 2) Icon Gallery, and copy the “Primary Glyph” for this icon?

Go ahead and click it, and then paste it into some text editor. Here’s what you get: 


Another ligature! (Does “face-grin#” makes sense now too?) This ligature is just “beer-mug-empty” (the icon’s name), ending with a single hashtag (octothorp, anyone?).

If you paste that ligature into a Desktop app where you’ve got Font Awesome 6 Duotone active, you’ll see the primary glyph.

Wanna guess what the ligature is for that icon’s secondary glyph? Yup:


Just add a second octothorp.

So you could go and click “Copy Secondary Glyph” in the Icon Gallery, or you could just type it into Illustrator. Either way, that’s how you reference the Duotone icon’s secondary glyph in Font Awesome 6 when using the Desktop OTF.

Now, in the case of this beer-mug-empty icon, there was a secondary unicode in FA5. If you’ve used those secondary unicodes, don’t worry, they’ll still work in FA6 because of unicode aliases. But let’s not get ahead of ourselves.

Webfonts in Font Awesome 6 (as of Beta 2) also use ligatures to reference those secondary glyphs, but we use a shorter ligature to reduce the byte sizes of the font and CSS files. So if you’re using pseudo-elements with Webfonts and you want that primary glyph, it’s a CSS rule like this:

 .beverage::before {
font-family: "Font Awesome 6 Duotone";
font-weight: 900;
content: "\f0fc";

And the secondary glyph like this:

 .beverage::before {
font-family: "Font Awesome 6 Duotone";
font-weight: 900;
content: "\f0fc\f0fc";

See? Just another ligature: a sequence of just two characters, the same unicode character repeated. Use the icon’s unicode character twice consecutively like this to tell the font that you want to see the secondary glyph for that icon.

What Happens to Font Awesome 5 Icon Secondary Unicodes? 

Icons from FA5 that had those secondary layer unicodes, like 10f0fc for the secondary layer of the beer-mug-empty icon — those still work. We’re building “unicode aliases” into our fonts to ensure compatibility.

For any icons new to FA6, there are no more secondary layer unicodes being assigned. Instead, we’re using ligatures as a way to reference the various glyphs that make up the layers of a multi-layer icon.

Problem: Level 2 — Emoji Standard Unicodes and Ligatures

Well, that was a lot of font tech to get ourselves out of the corner into which we painted ourselves. Relieved to be out of that corner, we turned around and found ourselves in another one.

Initially, we thought our solution with ligatures, allowing us to reference any number of glyph layers with a single icon name and a single unicode per icon, would then allow us to use the standard unicodes for all of those new emojis.

Unfortunately, we found that some web browsers handle some emoji characters specially. They didn’t like our fancy new ligatures when those ligatures began with a standard emoji unicode. Not all emoji unicodes, but a bunch of them. I suspect that this is because there are other fancy kinds of unicode sequences for emojis that allow for conceptual combinations. 

For example, a single emoji that looks like a “heart on fire” resulting from using a sequence of code points that correspond to the separate “heart” and “fire” emojis. Clever.

So that’s why we’re still using Private Use Area code points for our emoji icons. We want to make sure that when we make ligatures with them, font clients — like web browsers — do what we expect, instead of interpreting them according to some other special rules.

However, for many of those emoji icons, we do have unicode aliases defined. 

For example, that face-grin icon above has the standard emoji unicode of U+1F600. While the Font Awesome “canonical” unicode for face-grin is f580, if you’ve got that U+1F600 character in a document and you apply Font Awesome 6 to it, you’ll see that grinning face.

Solving These Problems = More Icons for You! 

The long and short of all this is … we needed to pivot how we use the available technologies to accomplish our goals for Font Awesome 6, which includes (but is not limited to) cranking out lots more icons, and making them easier to use in more ways. 

Go check out those new ligatures in Font Awesome 6 Duotone in your favorite desktop app, or upgrade to Pro to get access.

Get Pro