SvgSpriteEx
SvgSpriteEx lets you turn svg files into compile-time svg refs for Phoenix
components and LiveView.
You can render svgs in two ways:
ref={sprite_ref("...")}renders a<svg><use ... /></svg>wrapper backed by a generated sprite sheetref={inline_ref("...")}renders the full svg inline in the document
Installation
Add svg_sprite_ex to your dependencies:
def deps do
[
{:svg_sprite_ex, "~> 0.2.0"}
]
end
Then register the sprite compiler ahead of the default Mix compilers so it can
install its Elixir compile callback and discover sprite_ref/1, sprite_ref/2,
and inline_ref/1 usages.
def project do
[
app: :my_app,
version: "0.2.0",
elixir: "~> 1.19",
compilers: [:svg_sprite_ex_assets] ++ Mix.compilers(),
deps: deps()
]
end
Note that :svg_sprite_ex_assetsmust appear before the :elixir compiler.
When using Phoenix code reloading in development, add :svg_sprite_ex_assets
to reloadable_compilers. Phoenix only reruns the compilers listed there
during request-time reloads, so omitting it can still reload the page before
the generated sprite sheet or inline registry has been rebuilt.
config :my_app, MyAppWeb.Endpoint,
reloadable_compilers: [:svg_sprite_ex_assets, :elixir, :app]Adjust the list to match the compilers used in your project.
Configuration
import Config
config :svg_sprite_ex,
source_root: Path.expand("../priv/icons", __DIR__),
build_path: Path.expand("../priv/static/svgs", __DIR__),
public_path: "/svgs",
default_sheet: "sprites"Required configuration
source_root- absolute path to the directory that contains source svg files.build_path- absolute path where the compiler generates sprite sheets.public_path- public URL prefix forsprite_ref/1hrefs.
Optional configuration
default_sheet- default sprite sheet name when nosheetoption is given. Defaults tosprites.
Given the config above, if your svg file lives at
priv/icons/regular/xmark.svg, the logical svg name is regular/xmark.
Note that sprite_ref and inline_ref only accept compile-time literal
values. This is how the compiler discovers which svgs need to be included in
the generated outputs.
How it works
When you run mix compile, the compiler:
-
scans compiled modules for
sprite_refandinline_refcalls - hashes the referenced svg files and compiler inputs to detect asset changes
-
writes one svg sprite sheet per sheet name into
build_path - compiles generated modules for inline svg lookup and runtime metadata lookup
Your application must serve the generated files from the same public path you
configured. For example: Write sprite sheets into priv/static/svgs, and
serve them from /svgs.
Phoenix usage
Use SvgSpriteEx in any component, LiveView, or HTML module that renders svgs:
defmodule MyAppWeb.MyComponents do
use Phoenix.Component
use SvgSpriteEx
endThis will import:
-
the
<.svg>function component fromSvgSpriteEx.Svg -
the
sprite_refandinline_refmacros fromSvgSpriteEx.Ref
Render using a sprite sheet
defmodule MyAppWeb.MyComponents do
use Phoenix.Component
use SvgSpriteEx
def close_icon(assigns) do
~H"""
<.svg ref={sprite_ref("regular/xmark")} class="size-4" />
"""
end
end
By default the svgs are placed in a sprite sheet called sprites.svg, but you
can also compile svgs to other named sheets:
<.svg ref={sprite_ref("regular/xmark", sheet: "dashboard")} class="size-4" />Render inline svgs
Inline mode skips the sprite sheet and renders the svg inline in the document.
<.svg ref={inline_ref("regular/xmark")} class="size-4" />
This lets you serve the raw svg markup in the page instead of a <use>
reference, without doing runtime file reads.
Runtime metadata
SvgSpriteEx also exposes runtime metadata for compiled outputs:
SvgSpriteEx.sprite_sheets()
#=> [%SvgSpriteEx.SpriteSheetMeta{...}]
SvgSpriteEx.sprite_sheet("dashboard")
#=> %SvgSpriteEx.SpriteSheetMeta{...}
SvgSpriteEx.sprites_in_sheet("dashboard")
#=> [%SvgSpriteEx.SpriteMeta{...}]
SvgSpriteEx.inline_svgs()
#=> [%SvgSpriteEx.InlineSvgMeta{...}]
SvgSpriteEx.inline_svg("regular/xmark")
#=> %SvgSpriteEx.InlineSvgMeta{...}Patterns
Preload a single sprite sheet
When a layout or component knows it will use a specific sprite sheet, you can
preload it by looking up the compiled sheet metadata with sprite_sheet/1 and
rendering a <link rel="preload" ...> tag.
In a helper or function component:
defmodule MyAppWeb.MyComponents do
use Phoenix.Component
attr :sheet, :string, required: true
def sprite_sheet_preload(assigns) do
assigns = assign(assigns, :sheet_meta, SvgSpriteEx.sprite_sheet(assigns.sheet))
~H"""
<link
:if={@sheet_meta}
rel="preload"
href={@sheet_meta.public_path}
as="image"
type="image/svg+xml"
/>
"""
end
endThen in a layout or page template:
<.sprite_sheet_preload sheet="dashboard" />