Andrew Timberlake Andrew Timberlake

Hi, I’m Andrew, a programer and entrepreneur from South Africa, founder of Sitesure for monitoring websites, APIs, and background jobs.
Thanks for visiting and reading.

Use Font Awesome icons in Phoenix

It’s great that Phoenix comes with Heroicons support out the box, but I use Font Awesome and wanted to use those in the same way. This post will show you how you can swap out Heroicons and make a few changes so that the .icon component works with Font Awesome instead.

There are a few ways to use Font Awesome icons but this post will show you how to use the SVG icons hosted within your project in the same way that Heroicons work.

Step 1. Download the SVG files

Go to the Font Awesome download page and download the “version for the web” you’re going to use.
For this example, I’ll download the Free for Web version.

Step 2. Replace your Heroicon SVG files

  1. Delete the directory assets/vendor/heroicons
  2. Create a directory assets/vendor/fontawesome

Unzip the Font Awesome download and copy the contents of svgs/ into assets/vendor/fontawesome so you have:


If you’re using the pro version, then copy in the SVG directories you want to use.

Step 3: Modify your tailwind.config.js file

You need to update the paths from /vendor/heroicons to /vendor/fontawesome.
You need to change each icon variant, in this case we’re using regular as default, and changing -mini to -brand. You can add other Fonteawesome variants here as well, like -light.

The icon naming will change from hero-<name> to fa-<name>, hero-<name>-mini to fa-<name>-brand, and hero-<name>-solid to fa-<name>-solid.

@@ -34,12 +34,12 @@ module.exports = {
     // See your `CoreComponents.icon/1` for more information.
     plugin(function({matchComponents, theme}) {
-      let iconsDir = path.join(__dirname, "./vendor/heroicons/optimized")
+      let iconsDir = path.join(__dirname, "./vendor/fontawesome")
       let values = {}
       let icons = [
-        ["", "/24/outline"],
-        ["-solid", "/24/solid"],
-        ["-mini", "/20/solid"]
+        ["", "/regular"],
+        ["-solid", "/solid"],
+        ["-brand", "/brands"]
       icons.forEach(([suffix, dir]) => {
         fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
@@ -48,12 +48,12 @@ module.exports = {
-        "hero": ({name, fullPath}) => {
+        "fa": ({name, fullPath}) => {
           let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
           return {
-            [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
-            "-webkit-mask": `var(--hero-${name})`,
-            "mask": `var(--hero-${name})`,
+            [`--fa-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
+            "-webkit-mask": `var(--fa-${name})`,
+            "mask": `var(--fa-${name})`,
             "mask-repeat": "no-repeat",
             "background-color": "currentColor",
             "vertical-align": "middle",

Step 4: Modify your components file.

Do a search and replace across your core_components.ex file changing “hero-“ to “fa-“. The most important change is the icon/1 function which needs to match on "fa-". Note, not all the icons have a direct replacement so you may still need to find those icons and give them names that match the Font Awesome library.

@@ -585,13 +585,13 @@ defmodule MyApp.CoreComponents do

   ## Examples

-      <.icon name="hero-x-mark-solid" />
-      <.icon name="hero-arrow-path" class="w-3 h-3 ml-1 animate-spin" />
+      <.icon name="fa-x-mark-solid" />
+      <.icon name="fa-arrow-path" class="w-3 h-3 ml-1 animate-spin" />
   attr :name, :string, required: true
   attr :class, :string, default: nil

-  def icon(%{name: "hero-" <> _} = assigns) do
+  def icon(%{name: "fa-" <> _} = assigns) do
     <span class={[@name, @class]} />

Step 5: Use Font Awesome

You can now use any Font Awesome icons in your code with <.icon name="fa-rocket-solid" />

I hope that helps.

Step 6: Some modifications that may help

I found that to get the Font Awesome icons to work better in my project, I changed the Tailwind config a bit more.

I changed the icons to use mask-size and mask-position and then I use tailwind sizing on my icons. This change requires sizing be set for every icon, i.e. <.icon name="fa-icon" class="w-6 h-6" />

@@ -48,18 +48,18 @@ module.exports = {
         "fa": ({name, fullPath}) => {
           let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
           return {
             [`--fa-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
             "-webkit-mask": `var(--fa-${name})`,
             "mask": `var(--fa-${name})`,
             "mask-repeat": "no-repeat",
             "background-color": "currentColor",
             "vertical-align": 'middle',
             "display": "inline-block",
-            "width": theme("spacing.5"),
-            "height": theme("spacing.5")
+            "mask-size": "contain",
+            "mask-position": "center",
       }, {values})
12 Feb 2024