Inline Iconify SVGs for Phoenix and LiveView. Write a normal Phoenix component, let the compiler discover the icons you use, and ship only those icons with your app.
<.icon name="lucide:settings" class="size-5" />PhoenixIconify gives Phoenix apps access to 200,000+ icons from 150+ icon sets without a client-side icon runtime. Browse icons at icon-sets.iconify.design.
Most Iconify integrations load icons in JavaScript. PhoenixIconify keeps icons on the server:
- Icons are discovered from HEEx at compile time
- Only icons you use are fetched and stored
- Rendering is plain inline SVG
- SVG IDs are rewritten to avoid duplicate gradient/mask collisions
- No browser-side icon loader
- Works with LiveView diffs and
phx-*attributes - Dynamic icons can be pre-registered in config
It pairs naturally with Tailwind and Volt-powered Phoenix projects:
<button class="inline-flex items-center gap-2">
<.icon name="lucide:settings" class="size-4" />
Settings
</button>Add the dependency:
def deps do
[
{:phoenix_iconify, "~> 0.3.2"}
]
endAdd the compiler:
def project do
[
compilers: Mix.compilers() ++ [:phoenix_iconify]
]
endImport the component in your web module:
# lib/my_app_web.ex
defp html_helpers do
quote do
import PhoenixIconify, only: [icon: 1]
end
endNow use icons in HEEx:
<.icon name="lucide:settings" class="size-5" />Use Iconify's standard prefix:name format:
<.icon name="lucide:home" class="size-5" />
<.icon name="mdi:account" class="size-6 text-blue-600" />
<.icon name="heroicons:check" class="size-4" />Phoenix-style Heroicons names are supported too:
<.icon name="hero-user" class="size-6" />
<.icon name="hero-sun-mini" class="size-5" />
<.icon name="hero-sun-micro" class="size-4" />Global attributes are forwarded to the SVG, including phx-*, data-*, and aria-*:
<.icon name="lucide:x" class="size-4" phx-click="close" data-testid="close" />Use color for currentColor icon sets and inline when an icon should align with text:
<span>
Saved <.icon name="lucide:check" color="green" inline />
</span>Icons are decorative by default and render with aria-hidden="true":
<.icon name="lucide:settings" class="size-5" />For meaningful icons, provide label or title:
<.icon name="lucide:settings" label="Settings" />
<.icon name="lucide:settings" title="Settings" />Use Tailwind's size-* utilities when possible:
<.icon name="lucide:settings" class="size-5" />PhoenixIconify follows Iconify's dimension behavior. Icons default to 1em high and preserve their aspect ratio. Set one dimension and the other is calculated from the viewBox:
<.icon name="lucide:settings" size="20" />
<.icon name="lucide:settings" height="1em" />
<.icon name="lucide:settings" width="unset" />Iconify aliases can include transformations, and you can transform at render time:
<.icon name="lucide:arrow-right" rotate={1} />
<.icon name="lucide:arrow-right" flip="horizontal" />
<.icon name="lucide:arrow-right" h_flip />
<.icon name="lucide:arrow-right" v_flip />SVG mode is the default. CSS mask/background modes are available for Iconify-style CSS rendering:
<.icon name="lucide:settings" mode="mask" class="size-5" />
<.icon name="logos:elixir" mode="bg" class="size-5" />SVG IDs are replaced automatically, so icons with gradients, masks, clip paths, or animation references can be rendered multiple times on the same page.
- You write
<.icon name="lucide:settings" /> - The
:phoenix_iconifycompiler scans HEEx and~Hsigils - Literal icon names are collected
- Missing icons are fetched through Iconify
- A JSON manifest is written to
priv/iconify/manifest.json - At runtime, the component reads icons from the manifest and renders inline SVG
There is no client-side icon runtime and no JavaScript bundle impact.
Compile-time discovery only works for literal names. If an icon name comes from assigns, a database, or user configuration, register the possible values:
# config/config.exs
config :phoenix_iconify,
extra_icons: [
"lucide:check",
"lucide:x",
"lucide:alert-triangle"
]Then dynamic usage works at runtime:
<.icon name={@status_icon} class="size-4" />config :phoenix_iconify,
extra_icons: ["lucide:check", "lucide:x"],
fallback: "lucide:circle-help",
warn_on_missing: trueOptions:
:extra_icons- icons to include even when they are not found by static discovery:fallback- icon to render when a requested icon is missing:warn_on_missing- log missing icon warnings, enabled by default
PhoenixIconify stores:
priv/iconify/manifest.json- icons used by your apppriv/iconify/sets/*.json- cached icon sets
Useful tasks:
mix phoenix_iconify.prefetch # scan and fetch discovered icons
mix phoenix_iconify.audit # report discovered icons missing from the manifest
mix phoenix_iconify.clean # remove manifest icons no longer used
mix phoenix_iconify.list # list manifest icons
mix phoenix_iconify.stats # show manifest and cache statsCache tasks:
mix phoenix_iconify.cache fetch
mix phoenix_iconify.cache list
mix phoenix_iconify.cache clearFor projects created with Volt, PhoenixIconify is the server-rendered option:
<.icon name="lucide:settings" class="size-5" />It does not use Volt's JavaScript pipeline. If you want client-side icon components instead, use the official npm packages (iconify-icon, @iconify/react, @iconify/vue, etc.) through Volt's normal package handling.
MIT