Replacing country flag icons for emojis in a Phoenix web application

Santiago Bacaro
kommit
Published in
10 min readJul 17, 2020
Photo by Daria Sannikova from Pexels

Have you ever wanted to use country flags in forms that you wanted to present to your users? Perhaps in a country or a phone code select input? If you have, maybe you have resorted to icons and other things that did not make it quite easy for the flags to be included as select options, forcing you to use dropdowns instead, or something similar. I experienced it myself, and, while refactoring an old personal project, I decided to take another approach.

A bit of context

Before getting into the emojis, let me tell you the reason I came across this problem in the first place. Over a year ago, I was working on a side project, which required the users to provide some information (country, state, city, phone, etc.) as part of the signup process. And back then, when I started the project, I decided to build it as a Phoenix application, without LiveView. So, in my project I had a form for the location information that looked like this:

Screenshot of a register form asking for location details. There’s one field for country, one for region and one for city

As you may imagine, in order to reduce the payload size, the initial request only retrieved the list of countries and once the user selected one, the states/regions would be loaded, and similarly, the cities would only be loaded once the user had selected a state/region. But, in order to do this, Ajax requests were triggered when those fields changed, for which I had to create a couple of extra endpoints: one to provide the states/regions for a country and another one to fetch the cities for a country’s region.

That’s not too awful, I would even say that it probably continues to be a common practice (which may of course be made prettier with React or other front-end frameworks), but since working with LiveView in the last couple of months, I thought that this part was something that could be hugely simplified with it: firstly, because I could get rid of the Ajax requests that were being made, and secondly, I could get rid of those extra endpoints and just call my back-end functions to fetch states/regions and cities directly from the live views.

The pothole on the road

Unsurprisingly, when I was “on my way” to change that, I stumbled upon something that drew my attention and even though I tried to ignore it, I just did not have the heart to do it.

Before the location information, users were asked for some basic details:

Screenshot of a registration form which includes a dropdown with country flags as icons for selecting the phone code

As you may see, I added a dropdown to select the country’s phone code, and in order to make it friendlier to the user, I added an icon of the country’s flag along with the country’s ISO Alpha-2 code.

Getting this to work had its own hindrances. Namely, I wanted to include that icon, but regular HTML select inputs do not allow adding an icon to the options. Since I was using Bootstrap, I decided to go for a hacky solution: I would add a hidden input with the value of the phone code, and a dropdown full of buttons with each country’s phone code. That way I could bind the buttons’ click event to a simple JS function that would update the hidden input’s value and change the HTML of the dropdown so that it would display the selected option.

And as for the icons, an important part, of course, was to find a set of icons that I liked (if you’ve had to choose a set of icons, you’ll know you might spend much more time searching for it than writing the code to include it). I chose flag-icon-css, which I included using a CDN, and with that in place I could just throw in a span into the button with the icon I wanted to show. The code might show it better:

The most relevant lines are 9-18 and 31-36. In that first block, a button is added for each phone code using a span for the icons, and the onclick is assigned to the function defined in the second block, which takes in the phone code’s id and updates the item displayed in the dropdown, and the value of the input defined in line 3.

All of that to get something like this:

Screenshot of the extended dropdown with some flags and country phone codes

To be honest, I thought it looked quite nifty.

Shaming myself

When I looked back at this, I felt bad for having gone so far just to include an icon, and I honestly don’t know where the idea came from, but I thought like “hey, why not just remove the icons and use emojis?” after all, emojis are just represented using Unicode characters, which would allow me to use them in a regular select, and, after hundreds of times searching for emojis on social networks, I knew that country flags were part of the existing set of emojis.

What an emoji is made of

This idea of using emojis instead of icons taught me a couple of things. First, I learned how some emojis are built. If you have been using emojis for some time, and more likely if you have used Android or Slack or some platforms that haven’t fully supported emojis (or at least new ones) at some point, you might have noticed that some of them are actually a combination of other emojis, which I think is genius. For instance, take this handsome man right here:

👨🏻‍💻

You see him all professional with his laptop, thinking perhaps that he was just built like that. What you might not know is that he is actually a combination of this guy: 👨 with this skin tone: 🏻 and a computer: 💻.

And to show him with his computer and his pale skin, all you have to do is use the Unicode representation of all three of them in a single string, basically:

“👨 🏻💻”

I know, 🤯.

Which brings me to country flags. In order to see how the flag emoji would be represented in my application and my DB, I used “Santiago 🇨🇴” as a name in one of the forms, and found that it was stored like this:

Screenshot of the result of a DB query showing the flag emoji stored as emojis for the characters C and O

For those who might not be familiar with the flag, that’s Colombia’s flag, and not coincidentally at all, Colombia’s ISO Alpha-2 code is CO. This absolutely blew my mind. The emoji flags are just the combination of the emoji letters that make up the countries’ ISO alpha-2 codes.

GIF from Giphy

Removing the icons in favor of emojis

At this point I was very excited, as I already had the country ISO codes in my database, and therefore, showing their flags would just be a matter of converting to their emoji representations each of the letters that made up the codes.

Working with Unicode in Elixir

Elixir supports Unicode by default, and it provides some tools to work with it. For instance, you can use Unicode characters in a string by escaping their hex representation with \u, like so:

Screenshot showing conversion of a hex code to a character in an Elixir session

Here, we’re using the hexadecimal value ABCD to produce the Unicode character encoded by it.

This works fine for hexadecimal representations of up to 4 places. However, emojis typically use 5, so if we were to take for example the hexadecimal representation of “🤯”, which is 1F92F, it would not work as expected:

Screenshot showing a failed attempt at encoding an emoji from a hex code

What happens is that it takes the first 4 places and treats the last F as if it was not part of the Unicode character. Luckily for us, for this cases Elixir also allows us to use brackets to wrap all of the characters that should be considered as part of the Unicode character:

Screenshot of the emoji successfully encoded from its hex code

After learning this, I thought I would be able to just interpolate some code and be done with the flags. But I was wrong:

Screenshot of an error after trying to interpolate to a Unicode escape in an Elixir session

I don’t know why I did not foresee that was what would happen, but of course you cannot interpolate something into that, because you are already escaping the string. But, again, Elixir and Erlang save the day with charlists.

As you might already know, you can use ? in Elixir to get the codepoint of a character. So, for instance, to get the numerical value of the mind blown emoji, you can just do:

Screenshot of using the question mark to show the code point of an emoji in Elixir

But clearly, we can’t interpolate to this either, so let’s cut to the chase. What we can do, is use that value in a list which we can then convert to a string. Charlists in Erlang, and therefore in Elixir, are lists of code points. So, for instance, in Elixir, [129327] == '🤯' and also [104, 101, 108, 108, 111] == 'hello'. And we can simply use List.to_string/1 to convert any of those into a String with the contents. And similarly, we can use String.to_charlist/1 to convert the other way around.

With these handy functions, and knowing that the code point for the first emoji letter is 127462, that the one for the first uppercase letter is 65 and that the code points for all of the letters are consecutive, I was able to do something like:

"CO"
|> String.to_charlist()
|> Enum.map(&(&1 - 65 + 127462))
|> List.to_string()

With this, the logic from my template was reduced to this (the second file shows the function that was added to the view):

I would call that a significant improvement. The code that was used to create the dropdown and the list of buttons to populate it with the spans for the icons, was replaced by a single line using Phoenix.Html’s select. We generate the content for each option (both id and value) on this part:

Enum.map(@phone_codes, & {"#{make_flag(&1.country.code)} #{&1.country.code} (+#{&1.phone_code})", &1.id})

This generates a list of tuples {content, value} for each phone code with the content that will be displayed for it, and the value that the field will take. And we’re simply making a call to the function make_flag defined in the view as seen before.

And after a couple of minor CSS tweaks, the select was good to go:

Screen recording of the dropdown with emojis instead of icons for the flags

And that’s it. No Ajax requests, no endpoints that will only be used for that purpose, no calls to external APIs, no icons that need to be retrieved from a CDN or included with the application. All of that is gone.

One last improvement

The function that was defined to generate the emoji letters from the country codes was quite nice, and very idiomatic with those pipes, but there’s a better way. We can accomplish the same thing it did by defining a recursive function and working with the string as the binary it is:

Code inspired by this answer to a question on Elixir Forum https://elixirforum.com/t/how-to-use-streams-with-char-lists/17165/6

The default argument for the accumulator is an empty binary <<>>. Then we add a definition for the case when the binary is empty, in which case we return the accumulator. And finally we add a definition in which we pattern match the first character of the string received, and we append the utf8 character of the emoji representation for it to the accumulator. That way we don’t have to convert to a list, map its characters to their utf8 representation, and convert them back to a string; because we are working with binaries the whole time.

An arrow to the knee

Unfortunately, fairy tales are not real, and Microsoft still makes operating systems that continue to hold the highest market share among desktop OSs. When I tried to see the result in someone else’s PC that was running Windows 10, I noticed that the flags would not be displayed, and instead the emojis for the letters making up the country’s ISO Alpha-2 code would.

That is sad news, as I cannot just potentially deprive the statistical majority of my target audience of the joy of seeing those flags there. And after doing some quick research, I found this blog post which doesn’t really provide a reason as to why Windows won’t support flag emojis, but it suggests that it might be related to political issues that Apple faced related to them. But if that’s the case, I would be more than happy to have my to be opensource application not support Windows.

In the meantime I will dig deeper in the issue and try to find a workaround that does not force me to go back to the hacky dropdown solution, and if I find something that is worth an update, I will most certainly share it here. If you happen to know an alternative, please do let me know.

As a last comment, I would like to mention that in this blog post I used the terms related to text (character, Unicode, emoji, etc.) very loosely, but I found this fantastic GitHub page which provides a lot of insight into these elements of text and a much more specific terminology for them.

Also, I apologize to anyone who might be offended by my unsupportive Windows comments, but that OS and I have a history that I just cannot overlook.

If you read all of this, thank you!

--

--