Phoenix 1.7.1 - thank you for making Heroicons CSS-enabled

The title says it all :smiley:
Great thanks! Awesome job on 1.7.x. Thank you, thank you!

I was to report that z- class thing covers flash when <.modal> is open, but it’s an easy quick dirty edit fix. Plus phx-click-away on a <.modal> is too aggressive and hides itself when one taps a flash popup. Also an easy fix.

Side note: Would be cool to allow renaming attributes to _ prefix, to temporarily disable them :smiley: without causing warning complaints.


I still wanted to have the convenience of calling <Heroicons. and using auto-completion, and wrote a script for 1.7.1 to generate a Heroicons module that would restore those calls, but use a new, CSS way, vs the embedded <svg> elements.

The only thing I’m missing is how to make Tailwind aware of the used Heroicons and their classes when the app.css gets generated. Please, help!

i do not yet feel not so happy with that change.

my thoughts on that:

just had to rewrite the old HeroIcons-functions to the HeroIcons - Components, which was ok -
because, that’s what we do now: componentize all the things !

i was happy with the HeroIcons-Package as a fire-and-forget stable Icon-Solution
which has auto-completion, and warns on compilation if things break.

having those in some external directory and the need to update them constantly
feels like going back to the old icon-library woes i had with fontawesome
and the like in js/ruby/php land years ago.

i don’t find any issue, comment or discussion anywhere about the motivations
of that move (performance ? convenience ? nicer source ?) maybe there’s something
i’m missing ?

i don’t care so much about performance , i prefer to have a stable way
to reuse code from older projects and don’t have to fiddle too much
to make it work in a current one again.

the HeroIcons package felt like a good abstraction to
just copy-pasting svg in my templates (which ist super-stable, but would be really distracting :slight_smile:

i assume i can just stick with the old way, but don’t want to diverge too much
from the default setup for new projects.

The HeroIcons package approach works for client side frameworks but it doesn’t work for server side frameworks. With the package, we would send to the client the same svg several times, either in the same or separate pages. The way to address it by sending it as a regular image and have the browser cache it, as pretty much any server side framework does.

I am 100% certain that the new default provides better user experiences. Upgrading the icons is the only downside, but that rarely happens, and it is as easy as dropping a zip file. In any case, we are looking into streamlining it, potentially with a mix task.


I think the icons should be a depedency e.g. like how esbuild or tailwind are pulled in assets.


Icon packages like HeroIcons are a great upgrade to user experience, since it’s easier than inlining SVGs and one can go and use different ones available in HEX like Lucide Icons, etc. I even commited some PRs to HeroIcons to make upgrading easier, etc.

With this said, I understand the change for performance reasons, but like Kobrakai says, it would be nicer for it to be an external package with an easy way to update the icons, be it with new releases or in place with a mix script (what we have now but with the added script).
If Phoenix Components provides the Icon Component Function one could easily use different icon packages and still reap the performance benefits of this method.


I’ve been struggling at first too, that’s why wrote a script to restore Heroicons (while using new <.icon under the hood), but now I’m happy with the new approach as it accidentally made <span class="hero- possible, with auto-completion for free.

In fact, it’s even clearer now, as I don’t have to decide on mini or solid as an attribute anymore. It’s simply part of the class name.

Yes, I understand. Just bear in mind that there is no official package for heroicons. There are react and vue ones, with extra stuff in them, but not one with only icons (not even for npm). So someone would need to do the work (automatized or not) of converting new heroicons release and publishing that into packages.

So, for example, maybe heroicons release a new icon, but now you need to get a maintainer to update their package and ship a new version before using it.

So all of this, given the fact heroicons itself just tells you to download the whole thing, makes me a bit skeptical the package infrastructure is necessary here. Nonetheless, upgrades could be easier.


Some time ago I wrote a “component” that inlines heroicons for me: <%= heroicon("calculator_outline") %> but obviously it suffers the same problem you mentioned – it sends the same data multiple times, whenever/wherever the icon is supposed to appear. How is it done with this recent approach everyone talks about?

Through Tailwind plugin that registers a class with svg data inlined in a css inside a class instead of html. It watches for anything starting with hero- and ending with all possible variations of files.

Does Tailwind’s approach somehow allow styling the SVG? I don’t mean the container (eg. size) but the actual svg (eg. colour).

Since I haven’t found to do that so far using CSS (which we need in order to support multiple themes (eg. dark/light/high contrast/etc), I’ve ended up with a third approach in the icon lib I’ve put together, loading the SVGs as static files (so more initial HTTP requests but at least the browser can cache them) and using a workaround in JS to enabled styling them: Iconify for Phoenix — iconify_ex v0.0.2

Any feedback or advice would be appreciated!

Yes, it does. We use CSS masks for that. Generate a new app with Phoenix v1.7.1 or later and it should all be there.

1 Like

Ah thanks, I did see a mention of a workaround using masks on Stack Overflow, will explore more in that direction then!

PS: could you please point me to the masking code?

I am not sure if this is what you are looking for, but to add colors to a Heroicon, you may create a new project with e.g. the latest Phoenix 1.7.2 and use something like the following:
<.icon name="hero-magnifying-glass-circle-solid" class="w-5 h-5 bg-red-500" />

You can notice the new place of the icons at assets/vendor/heroicons.

I guess it should be relatively straightforward to modify an older project accordingly. Phoenix diff is your friend.

1 Like

Thanks :slight_smile: I like the use of a variable, didn’t want to have to repeat the SVG as I had seen in other examples!


I am using this code for a new app. I noticed that in the Chrome browser, the hero- class was not being rendered. On some digging around the interweb, I found that it’s because the # character in the mask image URL (for example the CSS class attribute mask here in mask: var(--hero-exclamation-circle-solid);) is treated as the fragment identifier (like &). I am locally fixing this by converting # into %23 characters for escaping by editing your above code like this.

 let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "").replace("#", "%23")

Is there any problem with the above code? It seems to work for me.


PS: Many thanks for the new liveview features.

Seems like the only heroicon file having # was arrow-left-circle, was it the trouble maker?

I can confirm Firefox wasn’t showing other icons for which I was also using the same plugin technique for, that had # in the content.

To be super safe (with a penalty of bigger size), base64 can be used, and I’m not happy with full elimination of \r\n and \n, I’d rather do one space instead:

let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, ' ')
return {
   [`--hero-${name}`]: `url('data:image/svg+xml;base64,${btoa(content)}')`,
// ...