How to inject SVG icon sprites in Angular component HTML DOM?

Zythyr picture Zythyr · May 22, 2018 · Viewed 9.6k times · Source

I am building an Angular application (Angular 4/5/6) and would like to use SVG sprites in my component template.

Question: Assuming I already have my SVG icon sprite generated (icons.svg), how can I get Angular to inject/import my SVG icon sprite into my component's template?

Is there a way to inject/import my SVG icon sprite into my component without having to use any 3rd party modules/directives and do it natively with Angular itself?

Background/Issue:

As discussed in this article, icons.svg file would contain all the SVG icons defined as <symbol>. Then I can render selected icons in my HTML using <use> assuming the icons.svg is injected in the DOM.

I generated SVG sprites using IcoMoon app, and saved the icons.svg into my Angular application. Below is my sample Angular component (app.component.ts) in which I am trying to inject/import the icons.svg file and trying to render the SVG icons in my HTML. However, Angular is not rending my SVG icons. I seems I am incorrectly injecting the SVG icon sprite file.

Updates:

  1. I am already aware of a similar question, SVG icon system with angular-cli, where the suggested answer was to use the Node module svg-sprite to generate a SVG sprites using the CSS mode. However, this is NOT what I am asking. I am NOT trying to generate the SVG sprites. I am trying get Angular components to be aware of my SVG sprite, icons.svg, and get it to render them in the HTML whenever I make use of them.
  2. A solution was suggested,https://stackoverflow.com/a/50460361/4988010, to generate a CSS font from the SVG sprite. I feel this is NOT a feasible solution and instead is a "workaround" to not being able to use the SVG sprite.

app.component.ts: Live example on StackBlitz: https://stackblitz.com/edit/angular-bbr2kh?file=src/app/app.component.ts

import { Component } from '@angular/core';
// import `./icons.svg`; // This import method doesn't work


@Component({
  selector: 'my-app',
  template: `

   <!-- This import method doesn't work -->
   <!-- <script src="./icons.svg"></script>  -->

  <p>
  Hello this is a sample Angular 6 component.
  </p>

  <p>Testing to see if SVG icon sprite import works. See below if icons appear. </p>
  <p>Icon (home): <svg class="icon icon-home"><use xlink:href="#icon-home"></use></svg> </p>
  <p>Icon (rocket): <svg class="icon icon-rocket"><use xlink:href="#icon-rocket"></use></svg> </p>
  <p>Icon (wifi): <svg class="icon icon-connection"><use xlink:href="#icon-connection"></use></svg>

  <!-- This import method doesn't work -->
  <!-- <p>Icon (home): <svg class="icon icon-home"><use xlink:href="./icons.svg#icon-home"></use></svg> </p>-->

   </p>
  `,
  styles: [`

  .icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  stroke-width: 0;
  stroke: currentColor;
  fill: currentColor;
  }

  `]
})
export class AppComponent {
}

Answer

Andy Braham picture Andy Braham · Aug 1, 2018

I think your root path is where you are having problems. In your code you are telling angular to look in app but the browser sees this as https://your-site.com./icons

If you move your icon file under your /assets folder, then it should be available already because the src\assets folder is already included in angular.json, the "assets" collection tells Angular where to look.

<svg class="icon">
   <use xlink:href="/assets/icons.svg#icon-rocket"></use> // Notice root path not "./"
</svg>

If you would like your files to be served from another directory all you need to do is add a path in your angular.json:

…
"assets": [
   "src/favicon.ico",
   "src/assets",
   "src/your-dir"
],
…

Then in your code

<svg class="icon">
   <use xlink:href="/your-dir/icons.svg#icon-rocket"></use>
</svg>

I wouldn't suggest adding /src/app as an asset path, this would basically open up your entire app for serving files, making your entire directory accessible.

I forked your example and updated here