Angular Library SVG Icons: my battle
SVG Icons in Angular Libraries: The Simple Solution I Missed For 3 Days Ever spent days solving what should be a trivial problem? This is the story of my three-day journey to make SVG icons work in an Angular library, which ultimately required just one line of configuration. The Challenge My task was straightforward: create a weather component library with a simple WeatherIcon component that would display different SVG icons based on a weather type input. @Component({ selector: 'weather-icon', template: '', }) export class WeatherIcon { @Input() type: 'sunny' | 'rainy' | 'cloudy' = 'sunny'; get iconPath() { return `assets/icons/${this.type}.svg`; } } The structure was clean: weather-lib/ ├── src/ │ ├── lib/ │ │ └── weather-icon.component.ts │ └── assets/ │ └── icons/ │ ├── sunny.svg │ ├── rainy.svg │ └── cloudy.svg I built the library, published it, imported it into my application, and... nothing. The icons wouldn't load. Every path returned a 404 error. The Investigation Day 1: Path Manipulation I started with the obvious – maybe the paths were wrong? I tried every permutation: // Version 1: Relative path iconPath = `./assets/icons/${this.type}.svg`; // Version 2: Root-relative path iconPath = `/assets/icons/${this.type}.svg`; // Version 3: Absolute path with origin iconPath = `${window.location.origin}/assets/icons/${this.type}.svg`; I checked network requests. The browser was looking for the files, but in locations where they didn't exist. The files were definitely in the NPM package – I could see them there. But Angular couldn't find them. Day 2: Exploring More Options As I moved into the second day, I began searching for answers in Angular documentation and forums. The official docs were surprisingly quiet about asset management in libraries. Stack Overflow had many similar questions, but most answers suggested the path manipulation techniques I'd already tried. I inspected the built NPM package and confirmed my SVG files were included. They were there, but somehow Angular couldn't see them. As desperation grew, I tried more complex solutions: Approach 1: Inline SVG Constants const ICON_MAP = { sunny: ` `, rainy: ` ` }; @Component({ template: `` }) export class WeatherIcon { @Input() type: 'sunny' | 'rainy' = 'sunny'; constructor(private sanitizer: DomSanitizer) {} getIcon() { return this.sanitizer.bypassSecurityTrustHtml(ICON_MAP[this.type]); } } This worked! But maintaining a library of SVG code snippets directly in TypeScript was neither elegant nor maintainable. Approach 2: Angular Material Icon Registry @Component({...}) export class WeatherIcon implements OnInit { constructor( private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer ) {} ngOnInit() { this.iconRegistry.addSvgIcon( 'sunny', this.sanitizer.bypassSecurityTrustResourceUrl('./assets/icons/sunny.svg') ); // Repeat for all icons } } Same issue. The paths still didn't resolve correctly. Day 3: The Epiphany After nearly three days of frustration, I reached out to a fellow developer. "Have you configured the assets in angular.json?" they asked. I stared at my screen, dumbfounded. Of course. Angular needs to know which assets to include when building the application that consumes my library. The Solution The entire solution was adding this snippet to the consuming application's angular.json: { "projects": { "my-weather-app": { "architect": { "build": { "options": { "assets": [ // Default assets "src/favicon.ico", "src/assets", // This is the magic line: { "glob": "**/*", "input": "./node_modules/weather-lib/assets/", "output": "/assets/" } ], } } } } } } With this single configuration change, all the SVG icons suddenly appeared as expected. The browser was now looking for them in the right location. Why This Happens Angular deliberately separates application assets from library assets. When you build an application: Angular processes the application's own assets folder It does NOT automatically include assets from libraries You must explicitly tell Angular to copy specific library assets to your build output This makes sense for optimization – you don't want to include every asset from every library dependency. But the documentation doesn't make this clear enough. What Worked For Me After this experience, here's what worked in my projects: Document asset dependencies: In your library's README, explicitly state that consumers need

SVG Icons in Angular Libraries: The Simple Solution I Missed For 3 Days
Ever spent days solving what should be a trivial problem? This is the story of my three-day journey to make SVG icons work in an Angular library, which ultimately required just one line of configuration.
The Challenge
My task was straightforward: create a weather component library with a simple WeatherIcon
component that would display different SVG icons based on a weather type input.
@Component({
selector: 'weather-icon',
template: '
',
})
export class WeatherIcon {
@Input() type: 'sunny' | 'rainy' | 'cloudy' = 'sunny';
get iconPath() {
return `assets/icons/${this.type}.svg`;
}
}
The structure was clean:
weather-lib/
├── src/
│ ├── lib/
│ │ └── weather-icon.component.ts
│ └── assets/
│ └── icons/
│ ├── sunny.svg
│ ├── rainy.svg
│ └── cloudy.svg
I built the library, published it, imported it into my application, and... nothing. The icons wouldn't load. Every path returned a 404 error.
The Investigation
Day 1: Path Manipulation
I started with the obvious – maybe the paths were wrong? I tried every permutation:
// Version 1: Relative path
iconPath = `./assets/icons/${this.type}.svg`;
// Version 2: Root-relative path
iconPath = `/assets/icons/${this.type}.svg`;
// Version 3: Absolute path with origin
iconPath = `${window.location.origin}/assets/icons/${this.type}.svg`;
I checked network requests. The browser was looking for the files, but in locations where they didn't exist. The files were definitely in the NPM package – I could see them there. But Angular couldn't find them.
Day 2: Exploring More Options
As I moved into the second day, I began searching for answers in Angular documentation and forums. The official docs were surprisingly quiet about asset management in libraries. Stack Overflow had many similar questions, but most answers suggested the path manipulation techniques I'd already tried.
I inspected the built NPM package and confirmed my SVG files were included. They were there, but somehow Angular couldn't see them.
As desperation grew, I tried more complex solutions:
Approach 1: Inline SVG Constants
const ICON_MAP = {
sunny: ``,
rainy: ``
};
@Component({
template: ``
})
export class WeatherIcon {
@Input() type: 'sunny' | 'rainy' = 'sunny';
constructor(private sanitizer: DomSanitizer) {}
getIcon() {
return this.sanitizer.bypassSecurityTrustHtml(ICON_MAP[this.type]);
}
}
This worked! But maintaining a library of SVG code snippets directly in TypeScript was neither elegant nor maintainable.
Approach 2: Angular Material Icon Registry
@Component({...})
export class WeatherIcon implements OnInit {
constructor(
private iconRegistry: MatIconRegistry,
private sanitizer: DomSanitizer
) {}
ngOnInit() {
this.iconRegistry.addSvgIcon(
'sunny',
this.sanitizer.bypassSecurityTrustResourceUrl('./assets/icons/sunny.svg')
);
// Repeat for all icons
}
}
Same issue. The paths still didn't resolve correctly.
Day 3: The Epiphany
After nearly three days of frustration, I reached out to a fellow developer.
"Have you configured the assets in angular.json?" they asked.
I stared at my screen, dumbfounded. Of course. Angular needs to know which assets to include when building the application that consumes my library.
The Solution
The entire solution was adding this snippet to the consuming application's angular.json
:
{
"projects": {
"my-weather-app": {
"architect": {
"build": {
"options": {
"assets": [
// Default assets
"src/favicon.ico",
"src/assets",
// This is the magic line:
{
"glob": "**/*",
"input": "./node_modules/weather-lib/assets/",
"output": "/assets/"
}
],
}
}
}
}
}
}
With this single configuration change, all the SVG icons suddenly appeared as expected. The browser was now looking for them in the right location.
Why This Happens
Angular deliberately separates application assets from library assets. When you build an application:
- Angular processes the application's own assets folder
- It does NOT automatically include assets from libraries
- You must explicitly tell Angular to copy specific library assets to your build output
This makes sense for optimization – you don't want to include every asset from every library dependency. But the documentation doesn't make this clear enough.
What Worked For Me
After this experience, here's what worked in my projects:
Document asset dependencies: In your library's README, explicitly state that consumers need to add library assets to their angular.json.
Document the solution in your code:
// Add a comment in your component explaining how to use it
/**
* WeatherIcon Component
*
* NOTE: To use this component, you must configure angular.json
* in your application to include the SVG assets:
*
* "assets": [
* // ... other assets
* {
* "glob": "**/*",
* "input": "./node_modules/weather-lib/assets/",
* "output": "/assets/"
* }
* ]
*/
Testing with Verdaccio: Don't Pollute npm
One of the most valuable lessons I learned was to test library changes locally before publishing to npm. Verdaccio is a lightweight private npm proxy registry that makes this process seamless:
# Install Verdaccio globally
npm install -g verdaccio
# Start the local registry
verdaccio
# In your library project, publish to local registry
npm publish --registry http://localhost:4873
# In your consuming application, install from local registry
npm install weather-lib --registry http://localhost:4873
This approach offers several advantages:
- No spamming the public npm registry with test versions
- Faster iteration cycle without waiting for npm cache updates
- Testing in a real application environment
- Ability to test multiple versions quickly
After confirming everything works with Verdaccio, you can confidently publish to the public registry.
Conclusion
What took me three days to figure out might take you just three minutes to implement after reading this. Angular libraries are powerful but have distinct differences from applications. Sometimes the solution isn't complex code but a simple configuration change.
Remember: when building Angular libraries with assets, you must tell the consuming application where to find those assets. One line in angular.json can save you days of debugging.