Injecting SVG With JavaScript

April 21, 2014 • By Joe Howard • In Web Development

“Injecting SVG” – it sounds kinda complicated I know, but trust me it’s not. It’s actually super-simple! Right now you’re probably thinking “Why would you use JavaScript to inject SVG markup? What is it? And how does it work?” Let me explain.


Advantages of inline SVG

From a deployment point-of-view, there are so many ways of implementing SVG into your projects, each with their own pros and cons. However much of our implementation decisions come down to 3 all important variables:

• HTTP requests.
• CSS and JavaScript customisation capabilities.
• Browser support.

If you want to meet all 3 of these requirements (assuming IE 9+ support), it’s fair to say that using inline SVG <svg> markup is the way forward. It meets all these requirements pretty well (and you could use .png fallbacks for browsers that don’t support it).


Disadvantages of inline SVG

Inline SVG can get a little messy and bloat your document, particularly on larger projects. It can also be a little difficult to manage, especially if you’re using PHP or other modular workflows. For example, if you want to change something, you need to trawl through all your various bits and pieces, find the respective SVG markup, change it, save it, find the relative CSS, clear caches, etc etc…

Furthermore there are other issues with inline SVG like the inability to defer loading and the effect this may have on page-loading. Additionally, if you’re not caching your HTML/XML markup, none of the SVG markup gets cached by the browser.

In summary the disadvantages are as follows:

Bloats document.
• Caching issues.
• Future changes can be time-consuming.
No deferred loading capability.
• Can make modular workflows over-complicated.
• Markup is spread across entire document, not stored in one place.


Wow, that disadvantage list looks a whole lot bigger than the advantages list. Luckily we can use JavaScript to inject the SVG data, eliminating all those disadvantages while retaining the advantages of inline SVG. Here’s how it works.


Open your SVG code

Download your favourite icon, design your own or whatever SVG’s you work with. This can be in either .ai (Illustrator) or .SVG format or whatever format you work from – Basically whatever way you get from a visual vector-based editor to SVG markup code.

If you’re working from Illustrator (or working with an SVG file created by Illustrator), you’ll probably get something like this:


<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="97px" height="97px" viewBox="0 0 97 97" style="enable-background:new 0 0 97 97;" xml:space="preserve">
<style type="text/css">
<![CDATA[
.my-circle{fill:#EC008C;}
]]>
</style>
<circle class="my-circle" cx="46.825" cy="48.016" r="32.954" blah blah blah.../>
</svg>

Quick-Tip: When saving as an SVG from Illustrator, click the “More Options” panel. Under the “CSS Properties” drop-down, select “Style Elements” then click “SVG Code“. This will automatically separate all the CSS styles from their elements, which you can then use in an external stylesheet.

seperating-SVG-CSS-with-Illustrator


Clean and minify that SVG

Once you’ve got your SVG markup, give it a clean up and minify the whole thing. There’s a code minifier here you could use. It should now look something like this:


<svg><circle class="mycircle" cx="46.825" cy="48.016" r="32.954" blah blah blah.../></svg>


Setup SVG-inject.js

Create a .js document and name it SVG-inject.js (or whatever else you want). First, cache a variable which will act as our target to inject the SVG into. Here I’ve used a unique ID as the variable. Then add an eventListener to check when the document has loaded.

Finally, paste your your SVG markup as the innerHTML content of that element. Note that if the SVG markup contains double quotation marks " ", it needs to be placed inside single quotation marks ' ' in JavaScript and vice versa.

Here’s how the basic function works:


var logo = document.getElementById("logo");

document.addEventListener('DOMContentLoaded', function(){

logo.innerHTML = 'SVG Code Goes Here';

});

Now, when we want our icon (logo) to appear all we need to do is create an element with the corresponding ID. Like this:


<span id="logo"></span>

JavaScript will then insert the SVG into that element when the document content has loaded.


Multiple Classes

The above example works on the notion that the target element is a unique ID, being only present once per document. However, you may need to inject the same SVG into multiple elements by class (e.g the same icon appearing multiple times on a page).

In this case the function would look like this:


document.addEventListener('DOMContentLoaded', function(){

var logo = document.querySelectorAll('.logo');

for (i = 0; i < logo.length; ++i) {

logo[i].innerHTML = 'SVG Code Goes Here';

}

});


Now any element that has the class .logo, will get the corresponding SVG markup injected as its contents.


Multiple SVGs/Icons

Finally, if you’re working with a lot of SVG content (e.g icons), your SVG-inject.js file should look something like this:


document.addEventListener('DOMContentLoaded', function(){

var icon1 = document.querySelectorAll('.icon1');
var icon2 = document.querySelectorAll('.icon2');
var icon3 = document.querySelectorAll('.icon3');

//icon 1
for (i = 0; i < icon1.length; ++i) {
icon1[i].innerHTML = 'SVG Code Goes Here';
}

//icon 2
for (i = 0; i < icon2.length; ++i) {
icon2[i].innerHTML = 'SVG Code Goes Here';
}

// icon 3
for (i = 0; i < icon3.length; ++i) {
icon3[i].innerHTML = 'SVG Code Goes Here';
}

});


You can still customise with CSS and JavaScript

As I said at the start, one of the best aspects of using an SVG is the ability to customise things through both JavaScript and CSS. Here is an example using a toggle/click function on injected SVG markup:


Working With Grunt

I’ve created a grunt plugin that automates this entire process. All you need to do is input a folder of .svg files and output a .js file. The plugin creates all the necessary JavaScript to inject that folder of SVGs. It will name the classes as .svg-[filename]. Take a look at the plugin over on GitHub here.


Conclusion

Injecting SVG via JavaScript is a great solution, particularly if you want to defer the loading of your SVGs until after the page has loaded (or even after the window has loaded). Furthermore, doing it this way retains all the features that make SVG so dynamic to begin with (like custom CSS styling and JavaScript functions). Here are some of the advantages:

Doesn’t bloat document.
All SVG markup is stored in a single document.
Markup is stored in a .js file, which is highly cacheable.
• Future changes are easier.
Loading can be deferred.
• Makes sense for modular workflows.
Super easy to use – (e.g create a class to insert SVGs anywhere).
• All SVG markup remains inline within your documents.
SVG markup gets minified (quicker loading) / caching.
A single HTTP request for all your SVGs.
• CSS and JavaScript customisation is retained.
Decent legacy support (optional fallbacks for I.E < 9).
Optional ability to minify JS in addition to SVG.
Optional ability to Gzip JS in addition to minifying everything.


 

 

About The Author

Joe Howard

Joe Howard is a hybrid designer, front-end developer and graphic designer. He's also the founder and editor of Pencil Scoop. You can follow him on your preferred social media platform.

Comments

  • http://eezy.com/ Shawn Rubel

    Hey Joe, amazing tutorial; going to pass this on towards my social stream. Just getting started with SVG; looks like the community is starting to adapt to it as well.

  • Mark Biesheuvel

    It’s funny reading this article because this is exactly what I implemented a couple of weeks ago for a client.
    For this project they wanted a railway map with different text balloons which could popup (enlarge to show more text).

    I ended up writing different Javascript classes which loaded their content from an svg file. Then I created a single Map Object and several Popup objects.

    This way made it also possible to use the same svg file to render different popups, all with slightly different properties.

    Once the client approves everything and the finished result is online, I could post an url if you’d like.

  • http://www.jonathan-dumaine.com Jonathan Dumaine

    Props for showing examples sans jQuery.

  • JJenZz

    You could do this with SVG sprites and and then you wouldn’t need JS to inject :) http://css-tricks.com/svg-sprites-use-better-icon-fonts/

    I like the idea of deferring icon loading though. If you still wanted to do that, you could inject the sprite with JS and then you’re only manipulating the DOM once instead of for every icon.