Skip to main content
Replaces the document favicon with the provided URL. On first run, existing icon links are removed and a dedicated favicon link is inserted into <head>. The link type is inferred from the file extension.

Usage

import { useFavicon } from '@kuzenbo/hooks';

function Demo() {
  useFavicon('/new-favicon.ico');

  return <div>Check the browser tab icon</div>;
}

Function Signature

function useFavicon(url: string): void

Parameters

url
string
required
Favicon URL to apply. The MIME type is automatically inferred from the file extension (.ico, .png, .svg, .gif).

Return Value

This hook does not return a value.

Examples

Basic Favicon Update

import { useFavicon } from '@kuzenbo/hooks';

function BrandedPage() {
  useFavicon('/brand-favicon.png');

  return (
    <div>
      <h1>Branded Page</h1>
    </div>
  );
}

Dynamic Favicon Based on Theme

import { useFavicon } from '@kuzenbo/hooks';
import { useColorScheme } from '@kuzenbo/hooks';

function ThemedApp() {
  const colorScheme = useColorScheme();

  useFavicon(
    colorScheme === 'dark' ? '/favicon-dark.svg' : '/favicon-light.svg'
  );

  return <div>App content</div>;
}

Notification Badge Favicon

import { useFavicon } from '@kuzenbo/hooks';
import { useState, useEffect } from 'react';

function InboxApp() {
  const [unreadCount, setUnreadCount] = useState(0);

  useFavicon(
    unreadCount > 0 ? '/favicon-notification.png' : '/favicon.png'
  );

  return (
    <div>
      <h1>Inbox ({unreadCount})</h1>
    </div>
  );
}

Status Indicator Favicon

import { useFavicon } from '@kuzenbo/hooks';
import { useState } from 'react';

type Status = 'online' | 'away' | 'offline';

function StatusApp() {
  const [status, setStatus] = useState<Status>('online');

  const faviconMap: Record<Status, string> = {
    online: '/favicon-online.svg',
    away: '/favicon-away.svg',
    offline: '/favicon-offline.svg',
  };

  useFavicon(faviconMap[status]);

  return (
    <div>
      <select value={status} onChange={(e) => setStatus(e.target.value as Status)}>
        <option value="online">Online</option>
        <option value="away">Away</option>
        <option value="offline">Offline</option>
      </select>
    </div>
  );
}

Different Favicons Per Route

import { useFavicon } from '@kuzenbo/hooks';
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();

  const faviconMap: Record<string, string> = {
    '/': '/favicon.ico',
    '/admin': '/favicon-admin.png',
    '/settings': '/favicon-settings.png',
  };

  useFavicon(faviconMap[location.pathname] || '/favicon.ico');

  return <div>{/* App routes */}</div>;
}

Loading State Favicon

import { useFavicon } from '@kuzenbo/hooks';
import { useState, useEffect } from 'react';

function DataLoader() {
  const [isLoading, setIsLoading] = useState(true);

  useFavicon(isLoading ? '/favicon-loading.gif' : '/favicon.png');

  useEffect(() => {
    // Simulate data loading
    setTimeout(() => setIsLoading(false), 3000);
  }, []);

  return <div>{isLoading ? 'Loading...' : 'Data loaded'}</div>;
}

Environment-Based Favicon

import { useFavicon } from '@kuzenbo/hooks';

function EnvironmentApp() {
  const env = process.env.NODE_ENV;

  const faviconUrl =
    env === 'production'
      ? '/favicon.ico'
      : env === 'staging'
        ? '/favicon-staging.png'
        : '/favicon-dev.png';

  useFavicon(faviconUrl);

  return <div>Environment: {env}</div>;
}

Supported File Types

The hook automatically sets the correct MIME type based on file extension:
  • .ico - image/x-icon
  • .png - image/png
  • .svg - image/svg+xml
  • .gif - image/gif
If the extension is not recognized, it defaults to image/x-icon.

Notes

  • On first run, removes all existing favicon link elements
  • Creates a new <link rel="shortcut icon"> element in the document head
  • The favicon updates whenever the url parameter changes
  • Works isomorphically (safe for SSR)
  • If no <head> element exists, the hook does nothing

Build docs developers (and LLMs) love