Iconex (iconex v0.1.0)

Copy Markdown View Source

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

SetComponentNames
Lucidelucide/1"house", "arrow-up-right"
IBM Carboncarbon/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_app

This 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

carbon(assigns)

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 name
  • size integer pixel size applied to width and height (default 16)
  • class CSS class string, added after iconex 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 to 16.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

hint(set, names)

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.

lucide(assigns)

Renders a Lucide icon.

Attributes

  • name (required) kebab-case icon name, e.g. "house", "arrow-up-right"
  • size integer pixel size applied to width and height (default 24)
  • class CSS class string, added after iconex iconex-lucide
  • stroke_width stroke width, any positive number (default 2, or config :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 to 24.
  • class (:string) - Defaults to nil.
  • stroke_width (:any) - Defaults to 2.
  • Global attributes are accepted.

sprite_tag()

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>