Please allow me to summarize the working approaches as of September 2020 and also provide a third bonus approach :)
Option 1:
Include the Ionic library in your package.json
As others have mentioned, the problem is that we would be including the whole IONIC library to end up using only the icons.
Here's how
ng add @ionic/angular
Option 2: Use the Icon library directly as a WebComponent.
By using this way, the <ion-icon>
component is registered so that it can be used even in vanilla javascript.
This can be achieved by simply adding the following script to your index.html
<script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>
Then you can use the <ion-icon>
WebComponent inside your templates like
<ion-icon name="heart"></ion-icon>
By the way, you should also add schemas: [CUSTOM_ELEMENTS_SCHEMA]
to your app.modules.ts
configuration to avoid Angular complaining that 'ion-icon'
is not a known element.
Bonus (if you are using Angular Material):
The material icons aren't bad, but I particularly like the Ionic ones, especially their outline variant.
It may seem a little "hacky" but there's a way to use IONIC icons using mat-icon
The idea is to use MatIconRegistry
to register the IONIC icons as part of Angular Material.
If you only want to use two or three icons it's easy, in fact, there are some posts written about it here https://riptutorial.com/angular-material2/example/32566/using-svg-icons and here https://dev.to/elasticrash/using-custom-made-svg-icons-through-the-angular-material-library-2pif
However for those who need all the icons this method is not scalable, there is however another way to "feed" the MatIconRegistry
using matIconRegistry.addSvgIconSetInNamespace
The documentation is few but basically what we need is an SVG container with all the Ionic icons within (aka SVG Sprite)
The requirements are:
- Ionicons installed and part of your package.json
- A script that runs after every
npm install
and generates the sprite
- The code needed to register the Sprite in the
MatIconRegistry
- Style Adjustments
For the first point just run npm i ionicons
.
For the second one, make sure to save to following script to the root of your project, I named it postinstall.js
but you are free to choose the name you want.
Also, add the svgstore
package to your dev dependencies by running npm i svgstore -D
// postinstall.js
const fs = require('fs');
const path = require('path');
const svgstore = require('svgstore');
const normalizePath = (folderPath) => path.resolve(path.normalize(folderPath));
const SVG_INPUT_FOLDER = normalizePath('node_modules/ionicons/dist/ionicons/svg');
const SPRITE_OUTPUT_FOLDER = normalizePath('src/assets/images/');
const GENERATED_SPRITE_NAME = path.join(SPRITE_OUTPUT_FOLDER, 'ionic-icons.svg');
const sprite = svgstore();
console.log('Generating SVG Sprite');
fs.readdir(SVG_INPUT_FOLDER, function (err, files) {
if (err) {
return console.log('Ups, there was an error reading the Directory: ' + err);
}
files
.filter(el => /\.svg$/.test(el))
.forEach((file) => {
sprite.add(file.replace('.svg', ''), fs.readFileSync(`${SVG_INPUT_FOLDER}/${file}`, 'utf8').replace(/<title.*>.*?<\/title>/ig, ''));
});
fs.writeFileSync(GENERATED_SPRITE_NAME, sprite);
console.log('Sprite generated successfully');
});
This script reads all the SVGs contained in the node_modules/ionicons/dist/ionicons/svg
folder and saves the sprite as src/assets/images/ionic-icons.svg
.
As I said before this script shall run during every npm install
, this can be achieved by simply editing your package.json
file and adding "postinstall": "node postinstall.js"
in the scripts
section.
Almost there: Registration of the Sprite using MatIconRegistry
.
In my case, I have decided to create a module named Material and then import it into the app.module.ts
// material.module.ts
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { MatIconModule, MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
@NgModule({
declarations: [],
exports: [MatIconModule],
providers: [
{
provide: APP_INITIALIZER,
useFactory: configureMatIconRegistry,
multi: true,
deps: [MatIconRegistry, DomSanitizer]
}
]
})
export class MaterialModule {}
export function configureMatIconRegistry(
matIconRegistry: MatIconRegistry,
domSanitizer: DomSanitizer
): () => Promise<void> {
return (): Promise<any> => {
matIconRegistry.addSvgIconSetInNamespace(
'ionicon',
domSanitizer.bypassSecurityTrustResourceUrl('assets/images/ionic-icons.svg')
);
return Promise.resolve();
};
}
The relevant part is the configureMatIconRegistry
but I think is self-explanatory.
Last but not least: Styles
Our mat-icon is ready to be used like this:
<mat-icon svgIcon="ionicon:heart-outline"></mat-icon>
But, due to the way these icons are created (I mean the original SVGs) we need some style adjustments. Just make sure to put this in your global styles to target all mat-icons
across the app, don't worry "regular" Material mat-icons will remain unchanged.
// styles.scss
.mat-icon {
&[data-mat-icon-namespace="ionicon"] {
display: inline-block;
width: 24px;
height: 24px;
font-size: 24px;
line-height: 24px;
contain: strict;
fill: currentcolor;
box-sizing: content-box !important;
svg {
stroke: currentcolor;
.ionicon {
stroke: currentColor;
}
.ionicon-fill-none {
fill: none;
}
.ionicon-stroke-width {
stroke-width: 32px;
}
}
.ionicon,
svg {
display: block;
height: 100%;
width: 100%;
}
}
}
And that's pretty much it! Now, with every npm install
you will have all the Ionic Icons ready to be used with the <mat-icon>