Giter VIP home page Giter VIP logo

ng-svg-icon-sprite's Introduction

SVG icon sprite component for Angular 17+

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

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 17+. 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

ng-svg-icon-sprite's People

Contributors

aliaksandrantanovich avatar angular-cli avatar dependabot[bot] avatar jannicz avatar pumano avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ng-svg-icon-sprite's Issues

Upgrade angular to 13

I am upgrading my project from angular 12 to angular 13. I keep getting the error(attached is the screenshot of it). I don't want to use --force. Any timelines on how soon I can expect your library to upgrade from angular 12 to angular 13
Screenshot 2022-03-03 at 1 26 14 PM

Setting default sprite path via ngModule

Couldn't the default sprite path integration be done easier, like:

imports: [
    BrowserModule,
    IconSpriteModule.forRoot({ path: '/assets/foo' })
  ]

directly in the importing module?

Cache Busting with svg sprite?

After rolling out this awesome library, I've encountered an issue around cache busting.

Since I am referencing the sprite (which is a static file) with a normal path in the html template, it does not go through the normal webpack treatment of getting assigned a hash on each build.

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

I've found some workarounds that use require(!!file-loader!<path>) to get cache busting for my sprite. Only problem is I have to add more boilerplate everywhere I want to use the <svg-icon-sprite>. Workaround found here: https://blog.wishtack.com/2018/06/20/unleash-the-power-of-webpack-in-angular/

Is there another way to get cache busting with sprites?

Angular 9 support

Hi, can you add Angular 9 support for this library?

Currently when I'm doing npm install I got:

npm WARN [email protected] requires a peer of @angular/common@^8.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @angular/core@^8.0.0 but none is installed. You must install peer dependencies yourself.

thanks a lot.

[Accessibility] Unique title id problem

If we add same icon on many places , we get problem about unique id of title . For below example, we get many title tags with same id 'check-title'

[src]="'assets/images/common_sprite.svg#check'" [classes]="'icon-30'" [title]="'check icon'" [attribute]="[ ['aria-labelledby', 'check-title'], ['role', 'img'] ]" ></svg-icon-sprite>
[src]="'assets/images/common_sprite.svg#check'" [classes]="'icon-30'" [title]="'check icon'" [attribute]="[ ['aria-labelledby', 'check-title'], ['role', 'img'] ]" ></svg-icon-sprite>

How to change fill and storke properties using angular input

Hi, Great package. Congratulations. I love it.

I am trying to change the fill and stroke of ng-svg-icon-sprite as in the instructions, but getting nowhere. Given the component below, what do I need to do to be able to change the fill and stroke input dynamically:

  selector: 'pim-ng-svg-icon-sprite',
  template: `
    <div class="svg-scale">
      <svg-icon-sprite
        id="x"
        [style]="style"
        [src]="icon"
        [viewBox]="viewBox"
        [width]="width"
      ></svg-icon-sprite>
    </div>
  `,
  styles: [
    `
      .svg-scale {
        /*Scale down by 50%*/
        transform: scale(1);
      }

     <!-- does not work
      ::ng-deep #x {{
        use {
          fill: orange;
          stroke: black;
        }
      }
     -->
    `,
  ],
})
export class NgSvgIconSpriteComponentWrapper {
@input() fill = 'red'
@Input stroke = 'blue
  @Input() icon = 'fox'
  @Input() scale = 0.5
  @Input() style = 'color: #ab3030;'
  @Input() width = '24px'
  viewBox = '0 0 ${width} ${width}'
}```

Need to be supported in Angular 7

currently, my project already upgraded to Angular 7 and need this lib also to be updated to Angular 7. Please help to keep it update to date. Many thanks.

fill: currentColor in styles head tag prevents styling width css

I use multicolor pattern to keep fill attribute which set to currentColor. In css I change both, color and fill property to change dynamically 2 colors but there is css rule inserted in head by plugin

[_nghost-tnf-c1] svg[_ngcontent-tnf-c1], [_nghost-tnf-c1] use[_ngcontent-tnf-c1] {
fill: currentColor;
}

and it prevents my styles working, is there any setting to cancel this behavior?

Error when building a docker project that has the ng-svg-icon-sprite package

Hello. We use ng-svg-icon-sprite in our project. There was a problem that the docker container stopped building. When I run the docker build command, I get an "Cant import the named export from non Ecmascript module (only default export is available)" error. We have version 11 of Angular. There are suspicions that the problem is with dependencies. Could you suggest what can be done? Maybe we need to update Angular?

Update: We have been using the package for 2 years now, but the error appeared a couple of days ago
"ng-svg-icon-sprite": "^1.10.0",

Clipboard - 24 июня 2022 г , 17_04

StaticInjectorError in angular 6.0.4

ng-svg-icon-sprite works with angular 6.0.3
unfortunately in 6.0.4 there is an error
ERROR Error: StaticInjectorError[ViewContainerRef]:
StaticInjectorError[ViewContainerRef]:
NullInjectorError: No provider for ViewContainerRef!

Could you please check?

SVG animateTransform tag missing

Animation tag was missed in <svg-icon-sprite [src]="'spin'" ></svg-icon-sprite>.

The sprite SVG output had animateTransform. But using "svg-icon-sprite", the animateTransform tag was missing. Transform animation missing and show single snap image-only,

I have download from internet and used for render, transform missing

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="50" cy="50" r="32" stroke-width="8" stroke="#fe718d" stroke-dasharray="50.26548245743669 50.26548245743669" fill="none" stroke-linecap="round" transform="rotate(311.837 50 50)">
  <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" keyTimes="0;1" values="0 50 50;360 50 50"></animateTransform>
</circle></svg>

Plz, suggest how to use animate SVG to convert sprite.
Thanks.

Accessibility attributes issue

@jannicz First of all thanks for your package, fast response and Angular 9 support :)

I have some issue with dynamic accessibility attributes.

  1. It's okay that ng-reflect-attribute is cropped?
  2. Video should describe the issue - https://www.loom.com/share/28dbd121a453454bb14d9ba297c539aa . aria-labelledby updates only after page reload.

Do you have any suggestions maybe?

My icon template:

<svg-icon-sprite
  [src]="'logo'"
  [width]="'109px'"
  [height]="'13px'"
  [classes]="'font-color-light'"
  [attribute]="[['aria-labelledby', 'ticket_search_page.egyjegy_logo_grey.alt' | translate], ['role', 'img']]">
</svg-icon-sprite>

Ability to add multiple attributes to SVG element

Currently we can to add a single attribute to the <svg> tag with the [attribute] input. However it doesn't seem to be possible to add more than one attribute. If I add multiple [attribute] inputs to a svg-icon-sprite component (let's say i want to get both focusable="false" and aria-hidden="true"), only the first one works.

Is there a way to add multiple attributes, and if there isn't, could it be something to implement in future versions of ng-svg-icon-sprite?

Firefox not working

Hi, there are some Firefox bugs with the sprite.
You can open your example on https://jannicz.github.io/ng-svg-icon-sprite/ in Firefox 63.0.3 (Linux) and see that icons are different than on Chrome.
I think that you manually have to add viewBox for each icon on component, and also preserveAspectRatio to 'xMidYMid meet'.
At least that was my case on my project with same issues, but those things aren't easy to implement on each icon.

Hope to get some new info.

Support Angular 8

Hi,

can you support Angular 8 as well?
Now I have:

npm WARN [email protected] requires a peer of @angular/common@^7.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @angular/core@^7.0.0 but none is installed. You must install peer dependencies yourself.

Thx

Adding accessible description to SVG element

Hi and thanks for a great package!

I miss one thing which is the ability to automatically output an accessible text for screen readers etc. in SVGs that the svg-icon-sprite component generates.

  1. According to svg4everybody README, both title attribute and <title> tag need to be present for cross-device results. At the current version of the package it is possible to add a title attribute with the [attribute]
  2. According to this article, the best solution is to insert a visually hidden text inside the svg element (by using specific styling, here's an example).

It would be nice to have an additional @Input to the svg-icon-sprite component that would allow to set descriptive text with some method above.

Angular 7.2.0 Error: Importing IconSpriteModule which does not have an ngModuleDef

Hello!

I get the following error after I included IconSpriteModule to my AppModule

main.ts:11 Error: Importing IconSpriteModule which does not have an ngModuleDef
    at core.js:15106
    at Array.forEach (<anonymous>)
    at transitiveScopesFor (core.js:15103)
    at setScopeOnDeclaredComponents (core.js:15040)
    at flushModuleScopingQueueAsMuchAsPossible (core.js:14808)
    at Function.get (core.js:15208)
    at getComponentDef (core.js:1115)
    at verifyDeclarationsHaveDefinitions (core.js:14921)
    at Array.forEach (<anonymous>)
    at verifySemanticsOfNgModuleDef (core.js:14901)

Am I doing something wrong? Can someone help me?

Angular 11 support

Currently, when trying to do a npm install inside my project it fails (using node v15). That's because there is a hard dependency to angular 10 in the package.json.

I would be really happy if you could test and migrate to angular 11!

Regards
Felix

error - module not found

After updating to version 1.13.1, an error appeared that the module "ng-svg-icon-sprite" or associated type declarations.ts (2307) could not be found.
Judging by what was loaded into the package folder from npm, the build artifacts were published incorrectly (source code instead of build from dist folder)

Incompatible with Angular 17

`npm ERR! Found: @angular/[email protected]

npm ERR! node_modules/@angular/common

npm ERR! @angular/common@"^17.0.2" from the root project

npm ERR!

npm ERR! Could not resolve dependency:

npm ERR! peer @angular/common@"^16.0.0" from [email protected]

npm ERR! node_modules/ng-svg-icon-sprite

npm ERR! ng-svg-icon-sprite@"1.13.2" from the root project
`

Support for version 10?

Angular 10 is the latest LTS version. I don't know if ng-svg-icon-sprite is currently compatible with it or not

xlink support should be dropped

According to MDN docs for href, all browsers support the normal href directive since a few years now. Safari was the last one and they also support it since 2019. According to the MDN Docs for xlink:href the support for that will or can be dropped at any time and therefore the xlink:href should be removed or should only be used as a fallback.

Your library currently only uses xlink:href in the <use> tag.

Support for IE 11 with "compilerOptions" target = es5

Now I have an error, after run ng serve (Angular 9)

Compiling ng-svg-icon-sprite : module as esm5

Warning: Invalid constructor parameter decorator in /node_modules/ng-svg-icon-sprite/fesm2015/ng-svg-icon-sprite.js:
 () => [
    { type: IconSpriteConfig, decorators: [{ type: Optional }] }
]

Error: Error on worker #2: Error: getInternalNameOfClass() called on a non-ES5 class: expected IconSpriteService to have an inner class declaration

Change target from es5 to es2015 won't work for IE11

SVG sprite icon is empty

I installed every thing and sprites.svg image is generated but this

<svg-icon-sprite
  [src]="'assets/sprites/sprite.svg#facebook'"
  [width]="'40px'"
  [viewBox]="'0 0 80 80'"
></svg-icon-sprite>

give me empty DOM on the browser , While Im using Angular 5 and ng-svg-icon-sprite version 0.8.0

screen shot 2019-01-17 at 1 45 28 pm

Ability to add additional attributes to inside svg element

Hi,

first thing thanks for very good library :)
Would it be possible to add some additional property to component svg-icon-sprite which will dynamically add attributes to inner svg element? Right now we are struggling with the fact that unfortunately we need to be compatible with IE11 and it seems that when you tab between input controls svg element also catches focus - one workaround for it is adding tabindex="-1" (in IE11 it seems that only setting focusable to false helps)
svg issue
what you think?

linearGradient id can't be found in the build file

Hello,

I've been trying to use a gradient that our UI designer want me to use, and there are multiple linearGradient definitions inside of the file.

linearGradient contains an id that the path can rely on, the problem is as soon as I build the global file, this id seem to disappear.

Am I doing something wrong or should something be done to fix this ?
Thanks

linearGradient definition :

<linearGradient x1="-1.95527313e-05%" y1="49.9999902%" x2="100%" y2="49.9999902%" id="linearGradient-1">
            <stop stop-color="#A5B849" offset="0%"></stop>
            <stop stop-color="#637B49" offset="100%"></stop>
</linearGradient>

Usage :
<path d="..." id="Path" fill="url(#linearGradient-1)"></path>

Built file linearGradient line (no id) :

<linearGradient x1="-1.95527313e-05%" y1="49.9999902%" x2="100%" y2="49.9999902%"><stop stop-color="#A5B849" offset="0%"></stop><stop stop-color="#637B49" offset="100%"></stop></linearGradient>

Problem with Angular testing

Hello, I follow the instructions but is have a problem when trying to config the @NgModule for the specific test.

ERROR: 'NG0304: 'svg-icon-sprite' is not a known element:

  1. If 'svg-icon-sprite' is an Angular component, then verify that it is part of this module.
  2. If 'svg-icon-sprite' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.'

Note: Not working to import the IconSpriteModule or IconSpriteComponent.

Please, write me for more info.

Best regards

could the dynamic icon name auto complete by the function forRoot?

when i use like this:

Step 2: Use the component
Having a dynamic icon name:
<svg-icon-sprite [src]="'assets/sprites/sprite.svg#' + iconName"></svg-icon-sprite>

colud i setting a default sprite path for icons?
imports: [ IconSpriteModule.forRoot({ path: 'assets/sprites/sprite.svg' }) ]
and then having a dynamic icon name:
<svg-icon-sprite [src]="iconName"></svg-icon-sprite>

when i change iconName , the path did not combine 'assets/sprites/sprite.svg' and iconName, BUT just get the iconName.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.