npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

favico.ts

v1.0.0

Published

Modernized TypeScript port of Favico.js for badges and favicon animations.

Readme

Favico.ts

npm version license

A modern, framework-independent TypeScript successor to Favico.js.

Favico.ts adds notification badges, images, video frames, and webcam streams to the browser favicon. It preserves the familiar Favico.js API where practical while adding strict TypeScript types, SSR-safe imports, ESM/CommonJS builds, modern media APIs, and explicit cleanup.

Features

  • Notification badges with circle and rectangle styles
  • slide, fade, pop, popFade, and none animations
  • Custom colors, fonts, positions, and per-call options
  • Image, video, and webcam favicon sources
  • Strict TypeScript declarations
  • ESM and CommonJS exports
  • Optional browser-global build for legacy <script> usage
  • SSR-safe imports for Next.js, Nuxt, and other server-rendered frameworks
  • Explicit cleanup through destroy()
  • Legacy aliases for common Favico.js options and methods
  • No runtime dependencies

Live Demo

▶️ Try the Interactive Demo

The demo source code is available in the repository.

Try it locally

git clone https://github.com/erikyo/favico.ts.git
cd favico.ts
npm install
npm run build
npm run demo:dev

Installation

npm install favico.ts
pnpm add favico.ts
yarn add favico.ts

Quick start

import Favico from "favico.ts";

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

await favico.badge(5);

Calling asynchronous methods without awaiting them remains valid for legacy-style JavaScript:

void favico.badge(5);

Awaiting is recommended so initialization or rendering errors can be handled by your application.

Badges

await favico.badge(1);
await favico.badge(42);
await favico.badge(1200);
await favico.badge("NEW");

Clear the badge and restore the base favicon:

await favico.badge(0);
await favico.badge("");
await favico.badge(null);

Override options for one update:

await favico.badge(12, "fade");

await favico.badge(12, {
  animation: "pop",
  backgroundColor: "#2563eb",
  textColor: "#ffffff",
  type: "rectangle",
});

Per-call options do not modify the instance defaults.

Configuration

const favico = new Favico({
  backgroundColor: "#dc2626",
  textColor: "#ffffff",
  fontFamily: "Arial, sans-serif",
  fontStyle: "bold",
  type: "circle",
  position: "down",
  animation: "slide",
});

| Option | Type | Default | Description | | ----------------- | --------------------------------------------------- | -------------- | -------------------------------------------- | | backgroundColor | string | "#d00" | Badge background color. | | textColor | string | "#fff" | Badge text color. | | fontFamily | string | "sans-serif" | Badge font family. | | fontStyle | string | "bold" | Badge font weight or style. | | type | "circle" \| "rectangle" | "circle" | Badge shape. | | position | "down" \| "up" \| "left" \| "leftup" \| "upleft" | "down" | Badge position. | | animation | "slide" \| "fade" \| "pop" \| "popFade" \| "none" | "slide" | Default animation. | | element | HTMLLinkElement \| HTMLImageElement | null | Explicit target element. | | elementId | string \| false | false | ID of a legacy target element. | | onUpdate | (url: string) => void | undefined | Called when a favicon URL is generated. | | window | Window | current window | Alternate window for iframes or tests. | | fallbackSize | number | 32 | Canvas size when no readable favicon exists. |

Legacy aliases

| Favico.js option | Favico.ts option | | ---------------- | ----------------- | | bgColor | backgroundColor | | dataUrl | onUpdate | | win | window |

New code should use the modern names.

Updating options

favico.setOptions({
  backgroundColor: "#7c3aed",
  animation: "fade",
});

Unspecified options keep their current values.

The legacy API remains available:

favico.setOpt("bgColor", "#7c3aed");

favico.setOpt({
  animation: "fade",
  textColor: "#ffffff",
});

setOpt() is deprecated. Prefer setOptions().

Images

Use an image element:

const image = document.querySelector<HTMLImageElement>("#avatar");

if (image) {
  await favico.image(image);
}

Use a URL:

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

Use an ImageBitmap:

const response = await fetch("/images/status-online.png");
const blob = await response.blob();
const bitmap = await createImageBitmap(blob);

await favico.image(bitmap);
bitmap.close();

Images are fitted inside the favicon while preserving their aspect ratio.

Remote images need suitable CORS headers before a browser can draw them to a canvas and export the result.

Raw favicon URLs

Set an already prepared favicon without canvas rendering:

await favico.rawImageSrc("/icons/maintenance.svg");

A raw URL is not automatically adopted as the base image for later badges. Call reset() before returning to badge rendering:

await favico.reset();
await favico.badge(3);

Video

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

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

Stop video rendering:

favico.stopVideo();

Favico.js-compatible calls remain available:

await favico.video(video);
await favico.video("stop");

Favico.ts uses requestVideoFrameCallback() when available and falls back to requestAnimationFrame().

Webcam

Camera access requires HTTPS or localhost and explicit user permission.

try {
  const stream = await favico.startWebcam({
    video: {
      facingMode: "user",
    },
    audio: false,
  });

  console.log(stream.getVideoTracks());
} catch (error) {
  console.error("Unable to start the webcam", error);
}

Stop the camera and release every acquired track:

favico.stopWebcam();

Legacy calls remain available:

await favico.webcam();
await favico.webcam("stop");

webcam() is deprecated. Prefer startWebcam() and stopWebcam().

Reset and cleanup

Restore the original favicon and stop active rendering:

await favico.reset();

Permanently release the instance:

favico.destroy();

destroy() cancels animations and frame callbacks, stops webcam tracks, removes listeners, restores modified favicon elements, and removes elements created by the library.

Calling destroy() more than once is safe.

React

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

interface NotificationFaviconProps {
  count: number;
}

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

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

    favicoRef.current = favico;

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

  useEffect(() => {
    const favico = favicoRef.current;

    if (favico) {
      void favico.badge(count);
    }
  }, [count]);

  return null;
}

Cleanup is important in React Strict Mode because development effects can be mounted, cleaned up, and mounted again.

Next.js

Favico.ts can be imported during server rendering, but DOM updates must run in a client component:

"use client";

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

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

  useEffect(() => {
    const favico = new Favico();
    favicoRef.current = favico;

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

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

  return null;
}

The package must not access window, document, or navigator during module evaluation.

CommonJS

The compatibility build supports the historical constructor pattern:

const Favico = require("favico.ts");

const favico = new Favico();
favico.badge(4);

Named access is also supported:

const { Favico } = require("favico.ts");

Browser-global build

For legacy pages without a bundler:

<link rel="icon" href="/favicon.ico">

<script src="https://cdn.jsdelivr.net/npm/favico.ts/dist/favico.global.min.js"></script>
<script>
  const favico = new Favico({
    animation: "pop",
  });

  favico.badge(7);
</script>

ESM imports are recommended for new projects.

API

| Method or property | Description | | --------------------------- | ---------------------------------------------------------------- | | ready() | Wait for the base favicon and renderer to initialize. | | badge(value, options?) | Render or clear a badge. | | image(source) | Render an image URL, image element, or ImageBitmap. | | rawImageSrc(url) | Assign a raw favicon URL. | | startVideo(video) | Start rendering frames from a video element. | | stopVideo() | Stop video rendering without altering the supplied video source. | | video(video \| "stop") | Favico.js-compatible video API. | | startWebcam(constraints?) | Start a webcam stream and return its MediaStream. | | stopWebcam() | Stop the webcam and its tracks. | | webcam(action?) | Deprecated Favico.js-compatible webcam API. | | setOptions(options) | Update defaults without resetting unspecified values. | | setOpt(key, value) | Deprecated Favico.js-compatible option setter. | | reset() | Stop active rendering and restore the original favicon. | | destroy() | Release the instance and every owned resource. | | isSupported() | Check whether the required browser features are available. | | browser.supported | Legacy support property. |

Error handling

Favico.ts exports typed errors:

import {
  EnvironmentError,
  FavicoError,
  ImageError,
  MediaError,
  RenderError,
} from "favico.ts";
try {
  await favico.image("https://example.com/remote-image.png");
} catch (error) {
  if (error instanceof ImageError) {
    console.error("The image could not be loaded", error);
  } else if (error instanceof RenderError) {
    console.error("The favicon could not be exported", error);
  } else {
    throw error;
  }
}

SSR behavior

Importing and constructing the class is safe outside the browser:

import Favico from "favico.ts";

const favico = new Favico();

Operations that require a DOM reject with an EnvironmentError instead of failing during import.

Content Security Policy

Favico.ts normally generates data:image/png URLs. A strict Content Security Policy may need to allow data images through the relevant img-src or fallback directive.

Test the final policy in each supported browser because favicon caching and policy handling can differ between engines.

Browser support and limitations

Favico.ts targets current Chromium, Firefox, and Safari/WebKit releases and should be tested in all three engines before each release.

Favico.ts updates the active document favicon. It does not replace:

  • installed PWA icons;
  • operating-system shortcuts;
  • pinned application icons;
  • mobile home-screen icons;
  • manifest icons.

Browsers may cache favicon changes differently.

Migration from Favico.js

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

favico.badge(5);
// Favico.ts
import Favico from "favico.ts";

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

await favico.badge(5);

| Favico.js | Favico.ts | | --------------------------- | ---------------------------------------------------- | | new Favico() | new Favico() | | badge(5) | await badge(5); ignoring the promise remains valid | | bgColor | backgroundColor; legacy alias preserved | | setOpt() | setOptions(); legacy method preserved | | image(img) | await image(img) | | rawImageSrc(url) | await rawImageSrc(url) | | video(video) | startVideo(video) or compatible video(video) | | video("stop") | stopVideo() or compatible video("stop") | | webcam() | startWebcam() | | webcam("stop") | stopWebcam() | | reset() | await reset() | | browser.supported | preserved | | CommonJS constructor export | preserved | | UMD/global script | browser-global compatibility build |

Development

npm install
npm run lint
npm run typecheck
npm test
npm run test:browser
npm run build
npm pack --dry-run

The npm archive must contain compiled dist/ files and must not rely on TypeScript source files at runtime.

Attribution

Favico.ts is a modernized derivative of Favico.js, originally created by Miroslav Magda.

The original MIT copyright and permission notice are retained.

License

MIT. See LICENSE.