DEV Community

Cover image for Inline SVG Icons in Your Rails App
Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

Inline SVG Icons in Your Rails App

This article was originally published on Rails Designer.


The SVG format is a great way to add icons to your app. Its vector limitations force you to keep them simple while still being able to change some attributes, like fill- and border color.

Widely supported for almost 20 years in all major browsers, there's really no reason to use anything else (image sprites anyone? πŸ˜‚)

In Rails there are currently two ways to display SVG's:

  • using image_tag;
  • directly add into the view (inline).

Using the image_tag is just like any other image in rails like so: image_tag "svgs/home.svg".

This is nice. It keeps the code clean and all icons neatly organized in app/assets/svgs. It has one big disadvantage though. You can't change its attributes, like fill or strokeWidth.

Bummer! 🫀

To get that functionality back, you can inline your SVG's like so

<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-8 p-1.5 bg-blue-50 text-blue-600 rounded-full">
  <path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
</svg>
Enter fullscreen mode Exit fullscreen mode

(icon taken from Heroicons)

Greatβ€”that's a good looking icon! But having SVG's like this in your views is messy (already have to deal with those hundreds of utility classes! πŸ€“).

Why not take the best of both worlds: write a little Ruby to inline SVG files!

Create a helper:

# app/helpers/icon_helper.rb
module IconHelper
  def icon(name)
    File.read(Rails.root.join("app", "assets", "svgs", "#{name}.svg")).html_safe
  end
end
Enter fullscreen mode Exit fullscreen mode

Now in your views you can write:

icon "home"
Enter fullscreen mode Exit fullscreen mode

Clean, right?! But there is no option to pass any attributes, like class for example. Let's extend the helper.

module IconHelper
  def icon(name, css: nil)
    file_path = File.read(Rails.root.join("app", "assets", "svgs", "#{name}.svg"))
    svg_file = Nokogiri::HTML::DocumentFragment.parse(file_path).at_css("svg")

    svg_file["class"] = css

    svg_file.to_html.html_safe
  end
end
Enter fullscreen mode Exit fullscreen mode

Now you can pass along (utility) classes to your icon:

icon "home", css: "size-8 p-1.5 bg-blue-50 text-blue-600 rounded-full"
Enter fullscreen mode Exit fullscreen mode

Amazeballs! 🍭

There's a gem for that!

Of course OSS to the rescue. πŸ›Ÿ Recently I published a little Rails gem to do all this for you. It's icon library agnostic, meaning you can use any icon library you want (opposed to other icon gems that limit to one library).

Currently it has first-party support for Heroicons, Lucide and Feather Icons.

Check it out at GitHub. 😺

Top comments (3)

Collapse
 
railsdesigner profile image
Rails Designer • Edited

Who here has used elaborate image sprites for their icons (mid-/late 2000's)? πŸ˜‚

Collapse
 
lexlohr profile image
Alex Lohr

I did create a method for scalable multi-color SVG sprite maps then. Just checked, my old employer is still using this system.

Collapse
 
railsdesigner profile image
Rails Designer

Love it! πŸ˜†