Angular Favicon Complete Guide
Master favicons in Angular: implementation for Angular 17+, dynamic favicon updates, SSR/SSG considerations, PWA setup, and best practices for modern Angular applications.
Quick Reference
Angular CLI
Add to /src/
Configure in angular.json
SSR/SSG
Use Meta service
Configure in server files
PWA
Use @angular/pwa
Auto-generates manifest
Standard Angular Implementation
Angular CLI Project Setup
Step 1: Add Favicons to /src/ Folder
/src/
favicon.ico
assets/
icons/
favicon-16x16.png
favicon-32x32.png
favicon-96x96.png
favicon-512x512.png
apple-touch-icon.png
android-chrome-192x192.png
android-chrome-512x512.pngStep 2: Update index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular App</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Favicons -->
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="assets/icons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="512x512" href="assets/icons/favicon-512x512.png">
<link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png">
</head>
<body>
<app-root></app-root>
</body>
</html>Step 3: Configure angular.json (Optional)
// angular.json
{
"projects": {
"your-app": {
"architect": {
"build": {
"options": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "src/assets/icons",
"output": "/assets/icons"
}
]
}
}
}
}
}
}Angular Advantage: Files in
assets array are automatically copied to output directory during build.
Dynamic Favicon Service
Change Favicon Programmatically
Create Favicon Service
// src/app/services/favicon.service.ts
import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class FaviconService {
constructor(@Inject(DOCUMENT) private document: Document) {}
setFavicon(href: string): void {
const link = this.document.querySelector("link[rel*='icon']") as HTMLLinkElement;
if (link) {
link.href = href;
} else {
const newLink = this.document.createElement('link');
newLink.rel = 'icon';
newLink.href = href;
this.document.head.appendChild(newLink);
}
}
setFaviconByType(type: 'default' | 'notification' | 'error'): void {
const icons = {
default: 'favicon.ico',
notification: 'assets/icons/favicon-notification.ico',
error: 'assets/icons/favicon-error.ico'
};
this.setFavicon(icons[type]);
}
}Usage in Component
// app.component.ts
import { Component, inject } from '@angular/core';
import { FaviconService } from './services/favicon.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
private faviconService = inject(FaviconService);
ngOnInit() {
// Change favicon on notification
this.faviconService.setFaviconByType('notification');
// Or use custom path
this.faviconService.setFavicon('assets/icons/custom-favicon.ico');
}
}Notification Badge Service (Advanced)
// favicon-badge.service.ts
import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class FaviconBadgeService {
constructor(@Inject(DOCUMENT) private document: Document) {}
drawBadge(count: number): void {
const canvas = this.document.createElement('canvas');
canvas.width = 32;
canvas.height = 32;
const ctx = canvas.getContext('2d');
if (!ctx) return;
// Load original favicon
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0, 32, 32);
if (count > 0) {
// Badge background
ctx.fillStyle = '#FF0000';
ctx.beginPath();
ctx.arc(24, 8, 8, 0, 2 * Math.PI);
ctx.fill();
// Badge text
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(count > 9 ? '9+' : count.toString(), 24, 8);
}
this.updateFavicon(canvas.toDataURL());
};
img.src = 'favicon.ico';
}
private updateFavicon(dataUrl: string): void {
let link = this.document.querySelector("link[rel*='icon']") as HTMLLinkElement;
if (!link) {
link = this.document.createElement('link');
link.rel = 'icon';
this.document.head.appendChild(link);
}
link.href = dataUrl;
}
reset(): void {
this.drawBadge(0);
}
}Server-Side Rendering (SSR/SSG)
Angular Universal Considerations
SSR-Safe Favicon Service
// favicon.service.ts (SSR-safe)
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class FaviconService {
constructor(
@Inject(DOCUMENT) private document: Document,
@Inject(PLATFORM_ID) private platformId: Object
) {}
setFavicon(href: string): void {
// Only execute in browser
if (isPlatformBrowser(this.platformId)) {
const link = this.document.querySelector("link[rel*='icon']") as HTMLLinkElement;
if (link) {
link.href = href;
}
}
}
}Meta Tags with Meta Service
// Using Angular Meta service for SEO
import { Component, OnInit, inject } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
private meta = inject(Meta);
ngOnInit() {
// Add meta tags for favicons (SSR-compatible)
this.meta.addTags([
{ name: 'msapplication-TileColor', content: '#2b5797' },
{ name: 'theme-color', content: '#ffffff' }
]);
}
}Important: Always check
isPlatformBrowser before manipulating DOM in SSR/SSG applications to avoid server-side errors.
PWA Favicon Configuration
Progressive Web App Icons
Step 1: Add PWA Support
ng add @angular/pwaStep 2: Configure manifest.webmanifest
// src/manifest.webmanifest
{
"name": "My Angular App",
"short_name": "AngularApp",
"theme_color": "#1976d2",
"background_color": "#fafafa",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}Step 3: Link Manifest in index.html
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">Angular 17+ Standalone Components
Modern Angular Approach
Standalone Favicon Service
// favicon.service.ts
import { Injectable, inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class FaviconService {
private document = inject(DOCUMENT);
setFavicon(href: string): void {
const link = this.document.querySelector("link[rel*='icon']") as HTMLLinkElement;
if (link) {
link.href = href;
} else {
const newLink = this.document.createElement('link');
newLink.rel = 'icon';
newLink.href = href;
this.document.head.appendChild(newLink);
}
}
}
// Usage in standalone component
import { Component, inject, OnInit } from '@angular/core';
import { FaviconService } from './services/favicon.service';
@Component({
selector: 'app-root',
standalone: true,
imports: [],
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
private faviconService = inject(FaviconService);
ngOnInit() {
this.faviconService.setFavicon('assets/icons/favicon-new.ico');
}
}Angular Favicon Best Practices
? Recommendations
- Use
@Inject(DOCUMENT)for DOM access - Check
isPlatformBrowserfor SSR - Place favicons in
/src/or/src/assets/ - Configure assets in
angular.json - Use Angular services for dynamic updates
- Add PWA support for app icons
- Test SSR build (
npm run build:ssr) - Leverage dependency injection
? Common Mistakes
- Direct DOM manipulation without DOCUMENT token
- Not checking platform in SSR apps
- Forgetting to add to
angular.jsonassets - Using
windowobject directly - Ignoring PWA manifest requirements
- Not testing production build
- Hardcoding paths instead of using assets folder
- Missing
providedIn: 'root'in services
Troubleshooting
Solutions:
- Ensure
favicon.icois in/src/folder - Check path in
index.htmlis correct - Verify
angular.jsonincludes favicon in assets - Clear browser cache (Ctrl+Shift+R)
- Restart Angular dev server (
ng serve)
Fixes:
- Use
@Inject(PLATFORM_ID)andisPlatformBrowser - Avoid direct
documentorwindowaccess - Use Angular's
DOCUMENTtoken - Test with
npm run build:ssr && npm run serve:ssr
Solutions:
- Verify service is injected correctly
- Check browser console for errors
- Add cache busting:
href + '?v=' + Date.now() - Ensure code runs in browser (not server)
Generate Angular-Ready Favicons
Create complete favicon package optimized for Angular applications
Generate for Angular