Ryan Trimble
various icons including a hearts, stars, arrows, and more, arranged in a grid with Figma guide markers visible

What the heck is an SVG sprite sheet?

Front End Development

If you work with me, you may have heard me mention SVG sprite sheets and wondered to yourself, “Man… he’s talking about SVG sprite sheets again, does Ryan not have any actually fun hobbies?”

And to that I say: “Thank you for asking about SVG sprite sheets.”

Now, am I a graphic designer? Not exactly, though I think I do a pretty well navigating SVGs.

SVG?

SVG, or Scalable Vector Graphic, is an XML-based way to describe two-dimensional graphics that stay crisp at any size (hence, “scalable” graphics).

The cool part, though, is browsers know what to do with SVGs and can render them like HTML elements. This allows developers to embed graphics directly, inline with other parts of a page. Also, as a generous bonus, we can style and adjust SVGs with cascading style sheets.

Sprite Sheets?

Sprite sheets are a way to have many graphics available from one resource and are used in many different ways.

In video games, sprites can be used for animating characters, actions, and environment elements. Sprite sheets have been used on the web for quite a long time as well.

An older technique for sprite sheets on the web involved having a grid of graphics within a single image file, then positioning the image in a way that showed only one graphic at a time. This was clever, though it was painful to manage.

SVG Sprite Sheets?

Combining the power of SVG with the concept of sprite sheets provides an effective way to deliver graphics, like icons, to our users.

SVG contains a feature called <symbol> which wraps around a graphic and turns it into something reusable, ideal for graphics such as icons. Adding an id attribute to the <symbol> gives us a way to reference the symbol.

We can mostly add as many icons as we want, though there are some warnings here:

  • Fairly complex graphics may add to the weight of the overall page.
  • Similarly, having a excessive amount of icons (think hundreds or thousands), will also cause performance issues

Combined with the <symbol> element, SVG also provides us a way to use the symbols, with <use> (duh, I guess). MDN says:

The <use> element takes nodes from within the SVG document, and duplicates them somewhere else. The effect is the same as if the nodes were deeply cloned into a non-exposed DOM, then pasted where the use element is, much like cloned template elements.

Neat! But wait, you might be thinking to yourself:

“I just remembered - writing SVGs by hand is a surefire path to madness, I thought you said this was cool”

…and you would be correct, this would be a pain to manage.

Luckily there are some great tools that can help us accomplish creating SVG sprite sheets so much easier.

Generators

There are several SVG sprite sheet generators online where you can upload your icon SVG files and it’ll spit out a sprite sheet.

I have used https://svgsprit.es/ for this type of thing previously, mostly as a quick way to get something together. A much more preferable way of creating these sprite sheets might be something a bit more automated.

Automating

So, I’m sure there are several ways to go about this, but the way I do this is by implementing this as a step within the build process.

I primarily use Vite as my build tool of choice, so let’s use that to build a SVG sprite sheet.

Setup

Let’s initialize a new Vite project for the purposes of this demonstration, but if you are already working on an existing Vite project, this will fit in nicely to your build process.

To create a new Vite project, navigate to your project directory and run the following in the terminal:

npm create vite@latest

Provide a name for the project and follow the prompts to complete. I named my project svg-sprite-sheets, selected to work with vanilla JavaScript, but feel free to select whatever matches your preferences or project requirements.

Navigate into the freshly created project and run npm install to install dependencies.

Plugins

One of the many reasons I prefer Vite is due to it’s vast community of developers who make awesome plugins and… hey would you look at that:

npm install -D vite-svg-sprite-wrapper

Yep, there is a Vite plugin to do exactly what we want to do, isn’t that convenient?

I love open source software! Shoutout to vshepel on Github for this Vite plugin!

Open up your project’s vite.config.js file, or if there is not one in your project directory, create a vite.config.js file and include the following:

import { defineConfig } from 'vite';
import ViteSvgSpriteWrapper from 'vite-svg-sprite-wrapper';

export default defineConfig({
	plugins: [
		ViteSvgSpriteWrapper()
	]
})

We need to pass in some options, specifically where to locate the icons and the output directory for the sprite sheet.

import { defineConfig } from 'vite';
import ViteSvgSpriteWrapper from 'vite-svg-sprite-wrapper';

export default defineConfig({
	plugins: [
		ViteSvgSpriteWrapper({
			icons: './src/icons/**/*.svg',
			outputDir: './public/'
		})
	]
})

The icons property points to the directory containing your SVG icons. We can use the **/*.svg syntax to recursively look for SVGs within the src/icons/ directory, if they happen to be nested into sub-directories.

For the outputDir, we can send the generated sprite sheet to Vite’s public/ directory. Anything within public/ is automatically copied, unprocessed, into the built dist/ folder, making the sprite sheet available to use within pages.

Now, whenever we run npm build to build the project, this plugin will do the following:

  • Grab all of the icons out of src/icons/
  • Combine and format the icons as <symbol> elements
  • Output a sprite.svg file to the public/ directory

Adding new icons

Just drop them into the src/icons/ directory and re-run the build!

Using Sprite Sheets

Now that we have a sprite sheet, let’s figure out how to actually use it.

I mentioned earlier that SVG has another feature called <use> that allows you to reference the id of a <symbol> inside our public/sprite.svg file.

If the sprite sheet is small enough, one thing you can do is embed it directly on the page, the you could do this:

<svg class="icon" aria-hidden="true">
	<use xlink:href="#arrow"></use>
</svg>

Which would copy the SVG symbol with the id of arrow inline, wherever you are using the icon.

This presents a problem though, anytime we update the sprite sheet, we would need to re-copy it’s code into the HTML somewhere - not ideal.

Instead, we can reference the path to the SVG and the id of the icon:

<svg class="icon" aria-hidden="true">
	<use xlink:href="./sprite.svg#arrow"></use>
</svg>

Note: Vite is smart enough to know where to find “public” files, so you do not need to include public/ within the path to the sprite sheet.

Now you should see the corresponding icon in the browser!

Other ways

You can embed an SVG sprite icon in several other ways as well:

<!-- as an image tag -->
<img src="./sprite.svg#arrow" />

<!-- as an iframe -->
<iframe src="./sprite.svg#arrow">
</iframe>

<!-- as an object -->
<object type="image/svg+xml" data="/sprite.svg#arrow">
	<!-- provide a fallback graphic -->
	<img src="./arrow.png">
</object>

Similarly, SVG sprite sheets can be used in CSS:

.element {
	background: url('./sprite.svg#arrow');
}

Let's work together!