Auto tree-shaken icons for Phoenix, from several icon sets.
Usage
Each icon set has its own component:
<Iconex.lucide name="house" class="w-5 h-5" />
<Iconex.lucide name="circle" size={20} />
<Iconex.carbon name="add" />
<Iconex.carbon name="arrow--right" size={20} />import Iconex lets you write <.lucide name="house" /> and
<.carbon name="add" /> instead.
Icon sets
| Set | Component | Names |
|---|---|---|
| Lucide | lucide/1 | "house", "arrow-up-right" |
| IBM Carbon | carbon/1 | "add", "arrow--right", "logo--github" |
Every set is enabled by default. To compile in only some of them:
# config/config.exs
config :iconex, sets: [:lucide]The component of a disabled set is not defined, and the compiler reports every call to it.
How it works
Mix.Tasks.Compile.Iconex reads your compiled modules after each build
and writes a pruned priv/static/images/iconex.svg containing only the
icons used, from every set. Register it after the default compilers in
mix.exs:
compilers: Mix.compilers() ++ [:iconex]Icons are rendered using svg
sprites via
<use> references to symbols named #<set>-<name>, e.g. #lucide-house.
Icon names are validated against the bundled data in priv/sets/; run
mix iconex.download SET to use a newer release of a set.
In the case of icon names that are dynamically called at runtime, such as a
conditional switching between two icons, you must hint the compiler, so it
emits both icons. See hint/2 for details.
Root layout setup
Place Iconex.sprite_tag/0 once at the top of <body>:
# root.html.heex
<%= Iconex.sprite_tag() %>Delivery modes
The default delivery is :external: sprite_tag/0 emits nothing and icons
reference /images/iconex.svg, which the browser fetches and caches once.
For development you can embed the sprite in the page instead, so no static file needs serving:
# config/dev.exs
config :iconex, delivery: :inline, otp_app: :my_appThis has added advantage that hot reloads can render new sprites without additional network requests.
In :inline mode sprite_tag/0 reads the pruned sprite from :otp_app
(at :output_path) and re-reads it whenever the compiler rewrites it.
Without :otp_app it embeds every icon.
:sets, :delivery, :sprite_url, and each set's :data_path (and
Lucide's :stroke_width) are read at compile time, so run
mix deps.compile iconex --force after changing them.
Per-set configuration
Options that apply to one set live under its id:
config :iconex,
lucide: [stroke_width: 1.5, extra_icons: ~w[loader]]Lucide stroke width
Every Lucide icon is drawn at stroke width 2, Lucide's own, unless the
stroke_width attribute says otherwise. Set an app-wide default with:
config :iconex, lucide: [stroke_width: 1.5]The width is in the 24-unit viewBox, so it scales with the icon.
Serving the static file
Phoenix's default Plug.Static setup serves priv/static/images, which is
where the sprite is written, so the defaults need no configuration.
If you serve static files from elsewhere, set both the file location and the
URL it is served at:
config :iconex,
output_path: "priv/static/assets/iconex.svg",
sprite_url: "/assets/iconex.svg"Icon data
mix iconex.download SET fetches a set's data. To use a copy newer than
the one bundled with iconex, point the set's :data_path at it (the path
must be absolute):
config :iconex, lucide: [data_path: Path.expand("../priv/iconex/lucide.json", __DIR__)]
Summary
Functions
Renders an IBM Carbon icon.
Marks icon names of set as used so the compiler includes them in the sprite.
Renders a Lucide icon.
Emits the SVG sprite element to be placed once in your root layout.
Functions
Renders an IBM Carbon icon.
Names are the @carbon/icons names, e.g. "add", "arrow--right",
"logo--github", matched case-sensitively. The 32px master artwork is
used at every size.
Attributes
name(required) Carbon icon namesizeinteger pixel size applied towidthandheight(default16)classCSS class string, added aftericonex iconex-carbon- Any other attribute is forwarded to the outer
<svg>element.
Examples
<Iconex.carbon name="add" />
<Iconex.carbon name="logo--github" class="text-gray-500" size={32} />Attributes
name(:string) (required)size(:integer) - Defaults to16.class(:string) - Defaults tonil.- Global attributes are accepted.
Marks icon names of set as used so the compiler includes them in the sprite.
Use it for names only known at runtime, next to the code that picks them:
icon = if @open, do: "chevron-up", else: "chevron-down"
Iconex.hint(:lucide, ~w[chevron-up chevron-down])The compiler only counts calls whose set is a literal atom and whose names
are literal strings, so ~w[...] works and names built at runtime don't.
Returns the list unchanged.
Renders a Lucide icon.
Attributes
name(required) kebab-case icon name, e.g."house","arrow-up-right"sizeinteger pixel size applied towidthandheight(default24)classCSS class string, added aftericonex iconex-lucidestroke_widthstroke width, any positive number (default2, orconfig :iconex, lucide: [stroke_width: ...])- Any other attribute is forwarded to the outer
<svg>element.
Examples
<Iconex.lucide name="house" />
<Iconex.lucide name="loader" class="loading-icon" size={20} />Attributes
name(:string) (required)size(:integer) - Defaults to24.class(:string) - Defaults tonil.stroke_width(:any) - Defaults to2.- Global attributes are accepted.
Emits the SVG sprite element to be placed once in your root layout.
In :inline delivery mode this embeds the sprite as a hidden <svg> block
so that <use href="#lucide-..."> fragment references resolve without an
extra HTTP request. The sprite is read from
priv/static/images/iconex.svg of the app configured as :otp_app, and
re-read whenever that file changes. Without :otp_app, or before the
compiler has written the file, every icon is embedded.
In :external delivery mode (the default) this emits nothing; the sprite is
served from :sprite_url and components reference it with a full path.
Place this at the very top of <body> in root.html.heex:
<body>
<%= Iconex.sprite_tag() %>
...
</body>