Svg sprites is the way
3 min read

Over the years, I have experimented with different ways to use svg icons in my projects. I have used importing as an image, inline svg, icon fonts and most recently, svg sprites. Each method has its pros and cons, but I have found that svg sprites are the most flexible and maintainable solution for my own projects.

I’m not going to reinvent the wheel here. There are plenty of blog posts by prominent developers on the topic. This is a more succint tdlr version of the topic for my own reference.

Image with SVG source

Logo.tsx
import Icon from './icon.svg';

export default function Logo() {
  return <img src={Icon.src} alt="My Logo" />;
}
  • Pros:
    • Easy to implement
    • Caching on subsequent requests (if done properly)
  • Cons:
    • Can’t style the svg with css.
    • Initial asset load waterfall can cause flicker or delay of asset display.

Inline SVG

Logo.tsx
export default function Logo() {
  return (
    <svg 
      width={24} 
      height={24}
      viewBox="0 0 24 24" 
      xmlns="http://www.w3.org/2000/svg" 
    >
      <path d="M10.464 8.746c.227-.18.497-.311.786-.394v2.795a2.252 2.252 0 0 1-.786-.393c-.394-.313-.546-.681-.546-1.004 0-.323.152-.691.546-1.004ZM12.75 15.662v-2.824c.347.085.664.228.921.421.427.32.579.686.579.991 0 .305-.152.671-.579.991a2.534 2.534 0 0 1-.921.42Z"/>
      <path fillRule="evenodd" clipRule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25ZM12.75 6a.75.75 0 0 0-1.5 0v.816a3.836 3.836 0 0 0-1.72.756c-.712.566-1.112 1.35-1.112 2.178 0 .829.4 1.612 1.113 2.178.502.4 1.102.647 1.719.756v2.978a2.536 2.536 0 0 1-.921-.421l-.879-.66a.75.75 0 0 0-.9 1.2l.879.66c.533.4 1.169.645 1.821.75V18a.75.75 0 0 0 1.5 0v-.81a4.124 4.124 0 0 0 1.821-.749c.745-.559 1.179-1.344 1.179-2.191 0-.847-.434-1.632-1.179-2.191a4.122 4.122 0 0 0-1.821-.75V8.354c.29.082.559.213.786.393l.415.33a.75.75 0 0 0 .933-1.175l-.415-.33a3.836 3.836 0 0 0-1.719-.755V6Z"/>
    </svg>
  );
}
  • Pros:
    • Can style with CSS (stroke, fill, etc…)
    • Part of the HTML document, displays immediately
  • Cons:
    • Increases the size of the HTML document
    • Increases the javascript bundle size

SVG sprites

Create a sprite file that contains all the svg icons you want to use.

Notice we use the symbol tag and an id to define the icon.

We also omit styles like fill and stroke from the svg. This allows us to style the icon with css.

sprite.svg
<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="github" viewBox="0 0 16 16">
      <path fill-rule="evenodd" clip-rule="evenodd" d="M8 0C3.58 0 0 3.57879 0 7.99729C0 11.5361 2.29 14.5251 5.47 15.5847C5.87 15.6547 6.02 15.4148 6.02 15.2049C6.02 15.0149 6.01 14.3851 6.01 13.7154C4 14.0852 3.48 13.2255 3.32 12.7757C3.23 12.5458 2.84 11.836 2.5 11.6461C2.22 11.4961 1.82 11.1262 2.49 11.1162C3.12 11.1062 3.57 11.696 3.72 11.936C4.44 13.1455 5.59 12.8057 6.05 12.5957C6.12 12.0759 6.33 11.726 6.56 11.5261C4.78 11.3262 2.92 10.6364 2.92 7.57743C2.92 6.70773 3.23 5.98797 3.74 5.42816C3.66 5.22823 3.38 4.40851 3.82 3.30888C3.82 3.30888 4.49 3.09895 6.02 4.1286C6.66 3.94866 7.34 3.85869 8.02 3.85869C8.7 3.85869 9.38 3.94866 10.02 4.1286C11.55 3.08895 12.22 3.30888 12.22 3.30888C12.66 4.40851 12.38 5.22823 12.3 5.42816C12.81 5.98797 13.12 6.69773 13.12 7.57743C13.12 10.6464 11.25 11.3262 9.47 11.5261C9.76 11.776 10.01 12.2558 10.01 13.0056C10.01 14.0752 10 14.9349 10 15.2049C10 15.4148 10.15 15.6647 10.55 15.5847C12.1381 15.0488 13.5182 14.0284 14.4958 12.6673C15.4735 11.3062 15.9996 9.67293 16 7.99729C16 3.57879 12.42 0 8 0Z"/>
    </symbol>
  </defs>
</svg>

Pass the name of the symbol to the use tag.

component.tsx
export default function Logo({name}: {name: string}) {
  return (
    <svg h={24} w={24} fill="currentColor">
      <use href={`/sprite.svg#${name}`} />
    </svg>
  );
}

  • Pros:
    • CSS styling
    • Keep all icons in a single file
    • Does not affect javascript bundle size
    • Can preload and cache the sprite file
  • Cons:
    • Not quite as fast as inline svg

Conclusion

I personally use a combination of inline svg and svg sprites in my projects.

I use inline svg for icons that are used once in a project, or when I need to apply more complex animations.

The rest of the time I use svg sprites for performance, easy styling and keeping all icons in a single file.

Ben Adam has a more in depth Article on the topic.