Inline SVGs without Trashing your Markup

SVGs are awesome, but if you want to get the most out of them, they should really be inline. Here's one way to do that that's not a huge hassle.

SVGs are great

By this point, you've probably heard a lot about why SVGs are great. We're not going to spend a lot of time on the nitty-gritty details, but here's a quick, non-exhaustive list of the reasons we love SVG:

  • They scale without losing fidelity.
  • They're tiny.
  • You can use CSS to affect them.

In our opinion, you should be using SVGs for any sort of vector art, rather than exporting to JPG, PNG, or the like. That said, there is one challenge with using SVGs: they're really best if you inline them in your document, but that makes your markup a huge mess.

We'd like to offer one solution to this issue.

Starting Very Generally

The first thing we want to do is create a few SVGs. In this case, a circle and a triangle. In each case, we made them in Illustrator and exported them with the Export for Screens tool. Next, we stripped out some extraneous stuff like data-name and the element's title. We also strip out any id or class attributes.

Here are the two SVGs we're going to work with:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><polygon points="24.9 0 0 50.5 49.8 50.5 24.9 0"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="25"/></svg>

Object Lesson

Next, we're going to create a standalone Javascript file, cleverly called svgs.js and create an object to hold these SVGs. Then we'll export that object for use in whatever file references it.

const svgs = {
    triangle: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><polygon points="24.9 0 0 50.5 49.8 50.5 24.9 0"/></svg>',
    circle: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="25"/></svg>'
}

export default svgs;

If you only have a couple SVGs, you could put this object in the same file as the function we're about to write, but our assumption is that you'll have lots of these things.

Now what?

Next, we're going to write a function that uses that object to spit out an SVG for us. For the purposes of customization, we want to also be able to assign a custom ID or class, so we're going to do a little string manipulation, replacing the opening <svg with our custom id and class (if they exist).

import svgs from "svgs";

function insertSvg(type, svgId = "", svgClass = "") {
    const svg = svgs[type].replace("<svg", `<svg id="${svgId}" class="${svgClass}"`);
    return svg;
}

Now any time we want to insert an SVG, we can just use this handy function. Of course, this gets even easier if you build it straight into your templating system. Speaking of...

Blaze

These days, most of our project use Meteor and Meteor's Blaze template library. In our use case, we'd create a global template helper that used the above function to return our SVG. Here's what the would look like:

Template.registerHelper( 'svgHelper', ( type, svgId, svgClass ) => {
  return insertSvg(type, svgId, svgClass);
});

And now any time we needed to insert an svg, we'd just do {{svgHelper "circle" "myCircle" "red"}} and we'd get the following in our page:

<svg id="myCircle" class="red" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><polygon points="24.9 0 0 50.5 49.8 50.5 24.9 0"/></svg>

Codepen

As usual, we've included a Codepen so you can see how it in action. Thanks for reading!

See the Pen Inlining SVG by Adrian Bettridge-Wiese (@arbw) on CodePen.

Further Reading

Interested in learning more about SVGs? Here are some great resources: