SVG in Rails. Gem inline_svg
In some cases you don’t want to use external SVG libraries like FontAwesome
Instead, you might want to use your own SVGs.
You can import SVGs into your apps’ assets folder:
<!-- app/assets/images/svg/search.svg -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.828 14.871l-4.546-4.545a6.34 6.34 0 10-.941.942l4.545 4.545a.666.666 0 00.942-.942zm-9.461-3.525a4.995 4.995 0 114.994-4.994 5 5 0 01-4.994 4.994z" fill="#272727"/>
</svg>
BTW, usually when I import an SVG, I:
- set
fill
tocurrentColor
- width/height in
em
instead ofpx
- remove
style
andclass
attributes
-fill="#FFFFFF"
+fill="currentColor"
-width="16px" height="16px"
+width="1em" height="1em"
The final SVG that is ready to be used in the app will look like this:
<!-- app/assets/images/svg/search2.svg -->
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.828 14.871l-4.546-4.545a6.34 6.34 0 10-.941.942l4.545 4.545a.666.666 0 00.942-.942zm-9.461-3.525a4.995 4.995 0 114.994-4.994 5 5 0 01-4.994 4.994z" fill="currentColor"/>
</svg>
To display the SVG, you can try to use image_tag
and render the SVG as an image:
<%= image_tag "svg/search.svg", style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= image_tag "svg/search2.svg", style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= image_tag "svg/search2.svg", style: "color: green; background-color: red; font-size: 40px;" %>
And here we see the problem: we can’t style the SVGs with CSS class
& style
:
To overcome this issue, we can use a helper that will parse an SVG, add html options and render it in html:
# app/helpers/svg_helper.rb
module SvgHelper
def svg_tag(icon_name, options={})
file = File.read(Rails.root.join('app', 'assets', 'images', 'svg', "#{icon_name}.svg"))
doc = Nokogiri::HTML::DocumentFragment.parse file
svg = doc.at_css 'svg'
options.each {|attr, value| svg[attr.to_s] = value}
doc.to_html.html_safe
end
end
<%= svg_tag 'search', style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= svg_tag 'search2', style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= svg_tag 'search2', style: "color: green; background-color: red; font-size: 40px;" %>
Now you see that the SVG was correctly rendered as an SVG in HTML:
Finally, instead of writing custom SVG helpers and “reinventing the wheel”, you can use an out-of-the-box solution: gem inline_svg
# terminal
bundle add inline_svg
<%= inline_svg_tag 'svg/search', style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= inline_svg_tag 'svg/search2', style: "color: green; background-color: red; height: 50px; width: 20px;" %>
<%= inline_svg_tag 'svg/search2', style: "color: green; background-color: red; font-size: 40px;" %>
Display all svgs in a view
class StyleguideController < ApplicationController
def index
@svg_names = Rails.root.join("app", "assets", "images", "svg").children.map { |path| path.basename.to_s.split(".")[0] }
end
end
<% @svg_names.each do |svg_name| %>
<%= inline_svg_tag "svg/#{svg_name}.svg", class: "h-6 w-6" %>
<%= svg_name %>
<% end %>
That’s it!
References: