ng-svg-icon-sprite

Angular 11+ package for generating and using inline SVG icons in your project

Usage no npm install needed!

<script type="module">
  import ngSvgIconSprite from 'https://cdn.skypack.dev/ng-svg-icon-sprite';
</script>

README

SVG icon sprite component for Angular 11

This library provides both a solution for generating SVG sprites and a module for including them.

Demo

Demo gif animation

Try out the ng-svg-icon-sprite demo

Use Cases

  • include single-color icons from a sprite
  • fill and scale icons dynamically via CSS (i.e. hover, focus effects)
  • meet accessibility requirements for inline SVGs

Installation

After installing the package as dependency you can import it into any application’s app.module.ts by simply including it in its @NgModule imports array:

import { IconSpriteModule } from 'ng-svg-icon-sprite'; // <-- here

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    IconSpriteModule // <-- here
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Usage

To use your SVGs from a sprite you need to:

  1. Convert your SVG icons into a sprite using a script
  2. Include the svg-icon-sprite component with the sprite path, and the icon name

Step 1: Generate the sprite

First add the library for sprite generation svg2sprite as a devDependency:

"devDependencies": {
  "svg2sprite-cli": "^2.0.1"
}

Each time you add an icon, you need to run the script generating the sprite. You might want to add it to your npm scripts:

"scripts": {
  "generate:svg-sprite": "svg2sprite ./src/assets/icons ./src/assets/sprites/sprite.svg --stripAttrs fill --stripAttrs stroke --stripAttrs id"
}

now execute the script:

npm run generate:svg-sprite

Note: only if the fill and stroke attributes are removed, the SVG can be styled via CSS. If don't need to apply color changes on your icons, go for the multi-color pattern described below

The script will take all SVG icons under src/app/assets/icons and create a sprite SVG into src/app/assets/sprites using the svg symbols technique:

app
└── assets
    └── icons (icons source)
        └── icon-1.svg
        └── icon-2.svg
    └── sprites (sprite destination)
        └── sprite.svg

Step 2: Use the component

Now you can include icons by using the svg-icon-sprite component directive:

<!-- include the icon named 'cart' -->
<svg-icon-sprite
  [src]="'assets/sprites/sprite.svg#cart'"
  [width]="'22px'"
  [classes]="'my-icon-class'"
></svg-icon-sprite>

Having a dynamic icon name:

<svg-icon-sprite [src]="'assets/sprites/sprite.svg#' + iconName"></svg-icon-sprite>

Options

  • src - icon source name, the syntax is path/file#icon where path is relative to app folder, file is the name of the sprite and icon is the filename of the svg icon.
  • width optional - width of the svg in any length unit, i.e. 32px, 50%, auto etc., default is 100%
  • height optional - the height of the svg in any length unit, if undefined height will equal the width
  • classes optional - class name(s) for this icon, default is icon
  • viewBox optional - define lengths and coordinates in order to scale to fit the total space available (use for scaling)
  • preserveAspectRatio optional - manipulate the aspect ratio, only in combination with viewBox
  • title - optional - text string that will be rendered into a title tag as the first child of the SVG node
  • attribute - optional - tuple or array of tuples containing key/value pair that should be added as an attribute on the SVG node, i.e. "['aria-hidden', 'true']" becomes <svg aria-hidden="true">

Styling

In order to change the icon color, add a CSS color property to the component invoking svg-icon-sprite. The SVG component uses the currentColor value to pass the ancestor's color through to the SVG shapes:

/* host component styles */
color: red;

Advanced Configuration

Assets folder

If you have another asset folder structure, set your input and output path in the npm script:

svg2sprite sourcefolder destination/filename.svg

Scaling and Sizing

If your SVG does not scale like expected (i.e. it is cropped or larger than desired) it might be lacking a viewBox. You need to set the viewBox attributes manually to match the size of the exported shape. A combination of the correct viewBox and width is required. Add the viewBox attribute and decrease/increase the last 2 values:

<!-- i.e. lower '0 0 80 80' to '0 0 40 40' to scale up/down -->
<svg-icon-sprite
  [src]="'assets/sprites/sprite.svg#star'"
  [width]="'40px'"
  [viewBox]="'0 0 80 80'"
></svg-icon-sprite>

See the viewBox example for further details. Still having trouble with scaling or sizing? Read this article about SVG scaling.

Dealing with multi color SVGs containing inline styles

If you wish use SVGs that contain inline styles (multi-color) that do not need to be overridden by CSS, provide a separate sprite file that keeps the stroke and fill attributes:

"scripts": {
  "generate:svg-multicolor-sprite": "svg2sprite ./src/assets/svg-images ./src/assets/sprites/image-sprite.svg"
}

The generated sprite will preserve its original styles, but you won't be able to style it via CSS that easily (demo).

Setting a default sprite path for all icons

If your app uses one sprite source, you can set its path in your @NgModule imports array:

imports: [
  IconSpriteModule.forRoot({ path: 'assets/sprites/sprite.svg' })
]

You can now leave out the path and just provide the icon name (demo).

<svg-icon-sprite [src]="'star'"></svg-icon-sprite>

Doing so you will still be able to override the default path by using the full syntax for particular icons that should use a different sprite file.

Browser Support

  • Chrome (63)
  • Firefox (57)
  • Safari 11
  • Edge

IE 11 support was removed in version 1.10.

Accessibility

In order to support screen readers and make the icons meaningful, you can use following patters:

  • add a title with descriptive text (demo)
  • optionally reference the title node using aria-labelledby=”icon-title”
  • optionally set the node's role to image (role=”img”)
<svg-icon-sprite
  [src]="'assets/sprites/sprite.svg#star'"
  [title]="'Some title text'"
  [attribute]="[['aria-labelledby', 'star-title'], ['role', 'img']]"
></svg-icon-sprite>

If you want to prevent the icon from being accessed by screen readers (i.e if you already have a descriptive text somewhere else), set the attribute of ['aria-hidden', 'true'] instead.

Or use combinations of several methods to achieve better results, like described in this article.

Compatibility

This library is optimized for Angular 11, for 10 use v. 1.9, for 9 use v. 1.8. If you combine multiple frameworks (i.e. React, Vue, etc.), it is recommended to use svg-icon-sprite web component instead!

Author & License

  • Jan Suwart | MIT License