Skip to content

Latest commit

 

History

History
239 lines (171 loc) · 6.17 KB

File metadata and controls

239 lines (171 loc) · 6.17 KB

PhoenixIconify

Hex.pm Documentation

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.

Why PhoenixIconify

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>

Installation

Add the dependency:

def deps do
  [
    {:phoenix_iconify, "~> 0.3.2"}
  ]
end

Add the compiler:

def project do
  [
    compilers: Mix.compilers() ++ [:phoenix_iconify]
  ]
end

Import the component in your web module:

# lib/my_app_web.ex
defp html_helpers do
  quote do
    import PhoenixIconify, only: [icon: 1]
  end
end

Now use icons in HEEx:

<.icon name="lucide:settings" class="size-5" />

Usage

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>

Accessibility

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" />

Sizing

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" />

Transformations and render modes

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.

How it works

  1. You write <.icon name="lucide:settings" />
  2. The :phoenix_iconify compiler scans HEEx and ~H sigils
  3. Literal icon names are collected
  4. Missing icons are fetched through Iconify
  5. A JSON manifest is written to priv/iconify/manifest.json
  6. 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.

Dynamic icons

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" />

Configuration

config :phoenix_iconify,
  extra_icons: ["lucide:check", "lucide:x"],
  fallback: "lucide:circle-help",
  warn_on_missing: true

Options:

  • :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

Cache and manifest

PhoenixIconify stores:

  • priv/iconify/manifest.json - icons used by your app
  • priv/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 stats

Cache tasks:

mix phoenix_iconify.cache fetch
mix phoenix_iconify.cache list
mix phoenix_iconify.cache clear

Volt projects

For 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.

License

MIT