---
# Meet Favico.ts: Bringing Dynamic Favicons Back to Modern TypeScript Applications

**URL:** https://modul-r.codekraft.it/meet-favico-ts-bringing-dynamic-favicons-back-to-modern-typescript-applications/
Date: 2026-07-11
Author: Erik
Post Type: post
Summary: More than a decade ago, Favico.js introduced a wonderfully simple idea: use the browser favicon as a tiny, dynamic notification surface. Unread messages? Put a badge in the favicon. A background task completed? Change the icon. A live video or webcam feed? Yes, even that could become the favicon. It was a clever library, and […]
Categories: Blog
Tags: development
Featured Image: https://modul-r.codekraft.it/wp-content/uploads/2026/07/favicots-banner.png
---

More than a decade ago, [Favico.js](https://github.com/ejci/favico.js) introduced a wonderfully simple idea: use the browser favicon as a tiny, dynamic notification surface.

Unread messages? Put a badge in the favicon.

A background task completed? Change the icon.

A live video or webcam feed? Yes, even that could become the favicon.

It was a clever library, and many developers used it. But the JavaScript ecosystem has changed considerably since then. Applications are now built with TypeScript, ES modules, server-side rendering, React, Next.js, Vue, Vite, and stricter expectations around lifecycle management and browser APIs.

That is why I created **Favico.ts**.

## A modern successor to Favico.js

Favico.ts is a modern, framework-independent TypeScript rewrite and evolution of Favico.js.

It keeps the original idea and preserves the familiar API wherever practical, while rebuilding the internals for modern frontend applications.

The goal was not simply to convert an old JavaScript file into TypeScript.

The goal was to make dynamic favicons useful again in current applications without giving up compatibility with existing Favico.js integrations.

You can explore the project here:

- **Live interactive demo:** [https://erikyo.github.io/favico.ts/](https://erikyo.github.io/favico.ts/)

- **GitHub repository:** [https://github.com/erikyo/favico.ts](https://github.com/erikyo/favico.ts)

- **npm package:** [https://www.npmjs.com/package/favico.ts](https://www.npmjs.com/package/favico.ts)

## Why would an application need a dynamic favicon?

The favicon is one of the few parts of a web application that remains visible even when the user is working in another tab.

That makes it surprisingly useful for communicating small pieces of state:

- unread messages;

- pending notifications;

- background jobs;

- support requests;

- shopping-cart updates;

- moderation queues;

- synchronization progress;

- new comments;

- monitoring alerts.

Instead of forcing users to repeatedly open a tab, the application can provide a subtle visual signal directly in the browser tab.

For example:

```
import Favico from "favico.ts";

const favico = new Favico({
  animation: "popFade",
  backgroundColor: "#ef4444",
  textColor: "#ffffff",
});

await favico.badge(5);

```

The favicon now displays a badge containing the number `5`.

Update the number when new notifications arrive:

```
await favico.badge(6);

```

Clear it when everything has been read:

```
await favico.badge(0);

```

## Built for modern applications

Favico.ts is framework-independent and has no runtime dependencies.

It can be used in a plain JavaScript application, but it is also designed to work cleanly with modern frameworks and build systems.

The package includes:

- strict TypeScript declarations;

- ESM and CommonJS builds;

- SSR-safe imports;

- React and Next.js compatibility;

- browser-global builds for legacy websites;

- explicit lifecycle cleanup;

- modern media APIs;

- typed errors;

- no runtime dependencies.

Importing the library does not immediately access `window`, `document`, or `navigator`, which means it can safely be imported in server-rendered applications.

Browser operations only happen when a favicon operation is actually requested.

## More than notification counters

Badges are the most obvious use case, but Favico.ts can do considerably more.

### Custom badge styles

Badges can use different shapes, colors, positions, fonts, and animations:

```
const favico = new Favico({
  type: "rectangle",
  position: "down",
  animation: "slide",
  backgroundColor: "#2563eb",
  textColor: "#ffffff",
});

await favico.badge("NEW");

```

Available animations include:

- `slide`;

- `fade`;

- `pop`;

- `popFade`;

- `none`.

Options can also be changed for a single update:

```
await favico.badge(12, {
  animation: "pop",
  backgroundColor: "#7c3aed",
});

```

### Use an image as the favicon

Favico.ts can display an image element, an image URL, or an `ImageBitmap`:

```
await favico.image("/images/user-online.png");

```

This could be useful for displaying:

- user avatars;

- connection states;

- task states;

- branded event icons;

- temporary application modes.

### Render video frames

A video element can become a live favicon source:

```
const video = document.querySelector<HTMLVideoElement>("#preview");

if (video) {
  await favico.startVideo(video);
}

```

Stop rendering when it is no longer needed:

```
favico.stopVideo();

```

The implementation uses modern browser frame callbacks when available and cleans up the rendering lifecycle explicitly.

### Use the webcam

Favico.ts also preserves one of the most unusual capabilities of the original library: rendering a webcam stream in the favicon.

```
const stream = await favico.startWebcam({
  video: true,
  audio: false,
});

```

And, importantly:

```
favico.stopWebcam();

```

Stopping the webcam releases the media tracks acquired by the library.

Naturally, webcam access requires HTTPS or localhost and explicit permission from the user.

## Designed with cleanup in mind

Modern frontend applications mount and unmount components frequently.

React Strict Mode, client-side navigation, hot module replacement, and dynamic layouts can easily expose libraries that do not properly clean up timers, event listeners, media tracks, or DOM changes.

Favico.ts therefore includes an explicit destruction lifecycle:

```
favico.destroy();

```

This cancels animations and frame callbacks, stops webcam tracks, removes listeners, and restores favicon elements managed by the instance.

In React, the integration can remain straightforward:

```
import { useEffect, useRef } from "react";
import Favico from "favico.ts";

export function NotificationFavicon({
  count,
}: {
  count: number;
}): null {
  const favicoRef = useRef<Favico | null>(null);

  useEffect(() => {
    const favico = new Favico({
      animation: "popFade",
    });

    favicoRef.current = favico;

    return () => {
      favico.destroy();
      favicoRef.current = null;
    };
  }, []);

  useEffect(() => {
    if (favicoRef.current) {
      void favicoRef.current.badge(count);
    }
  }, [count]);

  return null;
}

```

## Compatible with the old Favico.js API

One of the main objectives was to modernize the library without unnecessarily abandoning developers who used the original API.

Legacy option names and methods remain available where practical.

For example, old code may use:

```
var favico = new Favico({
  bgColor: "#d00",
  animation: "slide",
});

favico.badge(5);

```

Modern Favico.ts code can use:

```
const favico = new Favico({
  backgroundColor: "#d00",
  animation: "slide",
});

await favico.badge(5);

```

Legacy aliases such as `bgColor`, `setOpt()`, `webcam()`, and `browser.supported` remain available, while new code can use clearer modern equivalents.

The package also includes CommonJS and browser-global compatibility builds for projects that are not yet using ESM.

## Try it directly in your browser

The best way to understand a favicon library is to see it working.

I created an interactive playground where you can experiment with:

- badge values;

- badge colors;

- shapes;

- positions;

- animations;

- rapid notification updates;

- images;

- video;

- webcam input;

- reset and cleanup behavior;

- generated integration code.

While using the playground, keep an eye on the browser tab itself: the real favicon changes as you interact with the controls.

Try the demo here:

[https://erikyo.github.io/favico.ts](https://erikyo.github.io/favico.ts)

## Installation

Install Favico.ts from npm:

```
npm install favico.ts

```

Or with pnpm:

```
pnpm add favico.ts

```

Then import it:

```
import Favico from "favico.ts";

```

The repository contains more examples for React, Next.js, CommonJS, legacy browser usage, images, video, webcam streams, error handling, and migration from Favico.js.

## Open source and looking for real-world feedback

Favico.ts is open source and released under the MIT license.

This first release is also an invitation to test it in real applications.

I would especially appreciate feedback about:

- unusual browser behavior;

- framework integrations;

- favicon caching edge cases;

- SSR environments;

- accessibility considerations;

- missing compatibility cases from Favico.js;

- new use cases for dynamic favicons.

Bug reports, pull requests, documentation improvements, and feature ideas are all welcome.

If you find the project useful, consider starring the repository. It helps other developers discover the project and gives me a better idea of whether the library is worth continuing to expand.

- **GitHub:** [https://github.com/erikyo/favico.ts](https://github.com/erikyo/favico.ts)

- **Interactive demo:** [https://erikyo.github.io/favico.ts/](https://erikyo.github.io/favico.ts/)

- **npm:** [https://www.npmjs.com/package/favico.ts](https://www.npmjs.com/package/favico.ts)

Dynamic favicons may be a small detail, but sometimes the smallest parts of an interface are the ones users notice first.

---

## Categories

- Blog

---

## Navigation

- [Modul*R](https://modul-r.codekraft.it/)

## Tags

- development

---

## Footer Links

- [WordPress](https://wordpress.org/)