Contents
  1. The short answer
  2. A minimal favicon service
  3. Where the icon files live
  4. Why the icon sometimes does not update
  5. Choosing vector or raster variants
  6. Server-side rendering
  7. Using someone else's logo as the favicon
  8. Gaps in the available evidence

The short answer

Angular has no built-in favicon service. It provides Title and Meta services for the document head, but nothing for icons. To change a favicon at runtime, find the link element with rel set to icon in the document head and update its href, or create that element if it is missing. Do this through Angular's injected DOCUMENT token rather than the global document object, so the code fits Angular's dependency injection and does not assume a browser environment.

The favicon is a static file that the browser requests from the link element. Changing it dynamically means pointing that link at a different file, or at generated data, when application state changes. Typical triggers are a route change, a light or dark theme switch, a tenant or brand switch, or an unread-notification indicator.

A minimal favicon service

Wrap the DOM work in a root-provided service so components can call one method instead of each one querying the head:

import { Injectable, inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable({ providedIn: 'root' })
export class FaviconService {
  private readonly document = inject(DOCUMENT);

  setIcon(href: string, type = 'image/svg+xml'): void {
    const head = this.document.head;
    let link = head.querySelector<HTMLLinkElement>('link#app-favicon');

    if (!link) {
      link = this.document.createElement('link');
      link.id = 'app-favicon';
      link.rel = 'icon';
      head.appendChild(link);
    }

    link.type = type;
    link.href = href;
  }
}

The service targets a link element by id instead of the first rel=icon match. Many projects declare more than one icon link, such as an SVG icon and an ICO or PNG fallback. A generic selector could update the wrong one.

The matching markup in index.html looks like this:

<link id="app-favicon" rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="icon" type="image/x-icon" href="favicon.ico">

Calling the service is then a one-liner, for example from a component, a router event subscription or a signal effect:

private readonly favicon = inject(FaviconService);

onAlertsChanged(hasUnread: boolean): void {
  this.favicon.setIcon(hasUnread ? 'favicon-alert.svg' : 'favicon.svg');
}

Where the icon files live

The browser can only load favicon variants that the build copies to the output. Recent Angular CLI projects use a public folder for static files, while older projects use src/assets. Both are configured under the assets option in angular.json. Check which convention your project uses before writing paths into the service. A path that works in development but is missing from the build output fails silently, and the browser simply keeps the previous icon.

Why the icon sometimes does not update

  • Same href, no change: setting href to the value it already has does not make the browser re-request the file. If the file contents changed but the name did not, append a version query such as ?v=2.
  • Browser caching: favicons are cached aggressively. Use distinct filenames for distinct states rather than overwriting one file on the server.
  • Wrong element updated: with multiple rel=icon links, the browser chooses among them by type and support. Updating only the fallback, or only the SVG, can leave the visible icon unchanged in some browsers.
  • Format support: SVG favicon support and the handling of runtime favicon changes have varied between browsers, and Safari in particular has historically differed. The evidence supplied for this article gives no current version-by-version support data, so test in the browsers your audience uses.

Choosing vector or raster variants

SVG is a practical favicon format because one file scales to any tab or bookmark size. An SVG file can also include a prefers-color-scheme media query in its own styles, which adapts to the system theme without any Angular code. Use the dynamic service when the change depends on application state, such as an in-app theme toggle or an unread count, rather than on the operating system setting.

The .svg extension alone does not guarantee vector artwork. An SVG can wrap an embedded raster image, and that image will blur at larger sizes just like a PNG. Before relying on an SVG favicon, open it in a vector editor or read its markup, and confirm it contains paths and shapes rather than a single embedded image element.

Generating a badge by drawing on a canvas and converting it to a data URL produces a raster PNG, not vector output. That is acceptable at favicon sizes, but it is a different deliverable from an SVG variant. If a design team supplies the icon set, ask for each state as a separate vector file, such as default, alert and dark, simplified for very small sizes. Fine logo details and small text usually become illegible at tab-icon dimensions.

Server-side rendering

Because the service uses the injected DOCUMENT, it does not depend on a browser-only global. That makes it more robust when the app is rendered on the server. A favicon change only matters to a running browser tab, though, so state-driven updates such as notification badges typically belong in browser-side logic. Decide whether a server-rendered page should already ship with a state-specific icon or just the default one.

Using someone else's logo as the favicon

Swapping favicons per brand or tenant often means displaying logos you did not create. Being able to download a logo file does not mean you may modify it, recolor it, crop it into an icon or use its fonts and trademarks in your interface. Confirm usage rights with the brand owner or the relevant brand guidelines before creating altered favicon variants of third-party marks.

Gaps in the available evidence

The evidence supplied for this article contains no verified browser-support matrix, performance measurements or version-specific Angular behavior beyond the general approach described here. Treat the browser-compatibility notes as prompts to test, not as confirmed specifications, and check the current Angular documentation for the version your project targets.