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;" %>
Best approach: style SVG fill and stroke #
Don’t be afraid to edit SVG params. This is normal CODE!
Import an SVG and delete fill
, stroke
, class
attributes:
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" fill="none" stroke="currentColor" class="w-6 h-6">
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15.91 11.672a.375.375 0 0 1 0 .656l-5.603 3.113a.375.375 0 0 1-.557-.328V8.887c0-.286.307-.466.557-.327l5.603 3.112Z" />
</svg>
And use tailwind classes like stroke-sky-950 fill-rose-400
to update border (stroke) and background (fill) of the SVG:
inline_svg_tag 'svg/play-circle.svg', class: 'stroke-sky-950 fill-rose-400'
Result - custom colors for both border and background:
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:
Did you like this article? Did it save you some time?