Adding material symbols to a Phoenix project

Using Material Symbols with Phoenix and Tailwind CSS
Material Symbols is the variable font version of Google’s Material Icons. Unlike traditional icon fonts, variable fonts allow a single file to contain multiple stylistic variations—significantly reducing the number of assets you need to manage.
Material Symbols replaces the now-deprecated Material Icons fonts and is actively maintained with regular updates.
Why Use Material Symbols in Phoenix?
By default, new Phoenix projects include a set of built-in components, including an icon/1
component that renders Heroicons. While Heroicons are elegant and often sufficient, Material Symbols offer a far larger collection. They're widely adopted by UI designers, which means many mockups and design systems use them by default.
To preserve visual fidelity with the design, substituting icons between sets (like Heroicons and Material Symbols) is not ideal. Having Material Symbols available directly in your Phoenix app makes it easier to match designs precisely.
Material Symbols Overview
Material Symbols are based on 24px icons and come in three styles:
- Outlined
- Rounded
- Sharp
These are variable fonts with four axes of customization:
- Optical Size: Default is
24
- Weight: Default is
400
(Regular) - Grade: Default is
0
- Fill: Default is
0
For simplicity, we'll use the default values and only include the 400
weight icons.
Installing Material Symbols via Dependency
To avoid manually downloading and maintaining icon files, we can pull them directly from GitHub using a sparse checkout in mix.exs
. This setup fetches only the necessary svg/400
folder, avoids compiling the dependency, and reduces disk usage by limiting Git history.
Add the following to your mix.exs
dependencies:
{:material_icons,
github: "marella/material-symbols",
sparse: "svg/400",
app: false,
compile: false,
depth: 1
}
Then run:
mix deps.get
Extending the icon/1 Component
Phoenix comes with a built-in icon/1
component for Heroicons. We’ll add support for Material Symbols by introducing a new clause that matches icon names with a material-
prefix.
In core_components.ex, add this function:
def icon(%{name: "material-" <> _} = assigns) do
~H"""
<span class={[@name, @class]} aria-hidden="true" {@rest} />
"""
end
This allows you to use Material Symbols like so:
<.icon name="material-home" />
Configuring Tailwind to Recognize Material Symbols
Next, we need Tailwind to generate CSS classes for the Material Symbols. We’ll scan the SVG files in the deps/material_icons directory and create utility classes based on their filenames.
Update your tailwind.config.js with the following plugin:
plugin(function({ matchComponents, theme }) {
const path = require("path");
const fs = require("fs");
const iconsDir = path.join(__dirname, "../deps/material_icons/svg/400");
const values = {};
const styles = [
["", "outlined"],
["_rounded", "rounded"],
["_sharp", "sharp"],
];
styles.forEach(([suffix, dir]) => {
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
let name = path.basename(file, ".svg") + suffix;
name = name.replaceAll("_", "-");
values[name] = {
name,
fullPath: path.join(iconsDir, dir, file),
};
});
});
matchComponents({
"material": ({ name, fullPath }) => {
let content = fs.readFileSync(fullPath, "utf8").replace(/\r?\n|\r/g, "");
content = content.replace(' width="48" height="48"', "");
const size = theme("spacing.6");
return {
[`--material-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--material-${name})`,
"mask": `var(--material-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
"display": "inline-block",
"width": size,
"height": size,
};
}
}, { values });
})
With this setup, Tailwind will generate classes like material-home based on your icons. You can then use them as utility classes in your components.
Keeping Icons Up to Date
Since the Material Symbols repository is frequently updated via GitHub Actions, your app can stay current with new icons by simply running:
mix deps.update material_icons
Conclusion
Integrating Material Symbols with Phoenix and Tailwind gives you access to a vast and regularly updated icon set that aligns with modern UI design standards. By automating the dependency, icon rendering, and Tailwind class generation, you streamline both development and design fidelity—ensuring your front end looks just like the mockups.
Subscribe to my newsletter
Read articles from Ambrose Mungai directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
