This library provides both a solution for generating SVG sprites and a module for including them.
Try out the ng-svg-icon-sprite demo
- 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
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 { }
To use your SVGs from a sprite you need to:
- Convert your SVG icons into a sprite using a script
- Include the
svg-icon-sprite
component with the sprite path, and the icon name
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
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>
src
- icon source name, the syntax ispath/file#icon
wherepath
is relative to app folder,file
is the name of the sprite andicon
is the filename of the svg icon.width
optional - width of the svg in any length unit, i.e.32px
,50%
,auto
etc., default is100%
height
optional - the height of the svg in any length unit, if undefined height will equal the widthclasses
optional - class name(s) for this icon, default isicon
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 withviewBox
title
- optional - text string that will be rendered into a title tag as the first child of the SVG nodeattribute
- 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">
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;
If you have another asset folder structure, set your input and output path in the npm script:
svg2sprite sourcefolder destination/filename.svg
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.
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).
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.
- Chrome (63)
- Firefox (57)
- Safari 11
- Edge
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.
This library is optimized for Angular 17+. If you combine multiple frameworks (i.e. React, Vue, etc.), it is recommended to use svg-icon-sprite web component instead!
- Jan Suwart | MIT License