DEV Community

Ricardo Ruwer
Ricardo Ruwer

Posted on

SVG icons in Elixir and Phoenix

Here's the best way I can find to use SVG icons in Elixir and Phoenix framework:

First, you can create a file lib/myapp_web/helpers/icon_helper.ex:

defmodule MyAppWeb.Helpers.IconHelper do
  @moduledoc """
  Give some icons to be used on templates.
  """

  use Phoenix.HTML

  alias MyAppWeb.Router.Helpers, as: Routes

  def icon_tag(conn, name, opts \\ []) do
    classes = Keyword.get(opts, :class, "") <> " icon"

    content_tag(:svg, class: classes) do
      tag(:use, "xlink:href": Routes.static_path(conn, "/images/icons.svg#" <> name))
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

And then in your file lib/myapp_web.ex you can import this helper:

def view do
  quote do
    # ...

    import MyAppWeb.Helpers.IconHelper

    # ...
  end
end
Enter fullscreen mode Exit fullscreen mode

Now let's create our icons in the file assets/static/images/icons.svg:

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <svg id="active" viewBox="0 0 426 426">
    <path d="M213.333,0C95.518,0,0,95.514,0,213.333s95.518,213.333,213.333,213.333 c117.828,0,213.333-95.514,213.333-213.333S331.157,0,213.333,0z M174.199,322.918l-93.935-93.931l31.309-31.309l62.626,62.622 l140.894-140.898l31.309,31.309L174.199,322.918z"/>
  </svg>

  <svg id="right-arrow" viewBox="0 0 31 31">
    <path d="M21.205,5.007c-0.429-0.444-1.143-0.444-1.587,0c-0.429,0.429-0.429,1.143,0,1.571l8.047,8.047H1.111 C0.492,14.626,0,15.118,0,15.737c0,0.619,0.492,1.127,1.111,1.127h26.554l-8.047,8.032c-0.429,0.444-0.429,1.159,0,1.587 c0.444,0.444,1.159,0.444,1.587,0l9.952-9.952c0.444-0.429,0.444-1.143,0-1.571L21.205,5.007z"/>
  </svg>
</svg>
Enter fullscreen mode Exit fullscreen mode

I added 2 icons here, the active and the right-arrow, but you can add as many as you want.

Now all your views will have the icon_tag/3 so you can use in your HTML:

<%= icon_tag(@conn, "active", class: "something") %>
Enter fullscreen mode Exit fullscreen mode

or

<%= icon_tag(@conn, "right-arrow", class: "something") %>
Enter fullscreen mode Exit fullscreen mode

You can also add in your CSS file something like:

.icon {
  fill: currentColor;
}
Enter fullscreen mode Exit fullscreen mode

Then the SVG icon will be filled with the color used in your CSS :)
(As long as you don't use one fill="color" inside the <path> in your icons.svg)

And now, to finish, we can create a test file for the IconHelper module:

defmodule MyAppWeb.Helpers.IconHelperTest do
  use MyAppWeb.ConnCase, async: true

  import Phoenix.HTML, only: [safe_to_string: 1]

  alias MyAppWeb.Helpers.IconHelper

  test "icon_tag/2 renders a svg icon" do
    image =
      MyAppWeb.Endpoint
      |> IconHelper.icon_tag("active", class: "something")
      |> safe_to_string()

    assert image ==
             "<svg class=\"something icon\">" <>
               "<use xlink:href=\"/images/icons.svg#active\">" <>
               "</svg>"
  end
end
Enter fullscreen mode Exit fullscreen mode

Thank you @andrielfn for teaching it to me :)

Top comments (0)