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
-
Delete the directory
assets/vendor/heroicons
-
Create a directory
assets/vendor/fontawesome
Unzip the Font Awesome download and copy the contents of svgs/
into assets/vendor/fontawesome
so you have:
assets/vendor/fontawesome/brands
assets/vendor/fontawesome/regular
assets/vendor/fontawesome/solid
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 = {
})
})
matchComponents({
- "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
~H"""
<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 = {
})
})
matchComponents({
"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})