Ever built a slick React app, deployed it, and then noticed a blank white square in the browser tab instead of your beautiful brand icon? Or maybe your shiny new PWA just doesn't look quite right on an Android home screen? You're not alone. Getting your react favicon setup just right can feel like a game of whack-a-mole, especially with all the different devices and contexts out there.

Unlike a simple static HTML site, React applications (and other SPAs) have build processes and different ways of managing assets. This means a standard HTML <link> tag isn't always the full story. We need to consider how React's build tools handle static files and how we can add dynamic flair when necessary.

Prerequisites for a Perfect Favicon

Before we dive into the code, you'll want a few things ready:

Step-by-Step React Favicon Setup

Step 1: Generate and Prepare Your Favicon Assets

As I mentioned, a single icon won't cut it. Modern browsers and devices expect a range of sizes and formats. For instance, Chrome might grab a 32x32 PNG, while an iPhone home screen needs a specific Apple Touch Icon (180x180). You can learn more about the exact sizes in our Favicon Sizes Guide.

Use Mzu favicondl to generate a complete package from your source image. You'll get a zip file containing all the necessary PNGs, an ICO, and a manifest.json file. Extract these files to a temporary location.

Step 2: Place Your Favicon Assets in the public Folder

In most React setups (like Create React App or Vite), there's a special folder named public (or sometimes static). Files placed here are copied directly to the build output without being processed by webpack or Vite's bundler. This is precisely where your favicons and manifest.json belong.


public/
├── index.html
├── manifest.json
├── favicon.ico
├── apple-touch-icon.png
├── icon-192x192.png
├── icon-512x512.png
└── ... (other favicon sizes)

Just drag and drop all those generated favicon files and your manifest.json into your project's public folder. Easy peasy.

Step 3: Link Favicons in public/index.html

Even though React is a Single Page Application, it still relies on a base HTML file, usually public/index.html. This is where you'll add the <link> tags for your favicons and the web app manifest.

Open public/index.html and locate the <head> section. You'll likely see some default favicon links already there (especially with Create React App). Replace or augment them with your full set:


<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

  <!-- Other essential favicon sizes -->
  <link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/icon-16x16.png">
  <link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/icon-32x32.png">
  <link rel="icon" type="image/png" sizes="48x48" href="%PUBLIC_URL%/icon-48x48.png">
  <link rel="icon" type="image/png" sizes="96x96" href="%PUBLIC_URL%/icon-96x96.png">
  <link rel="icon" type="image/png" sizes="192x192" href="%PUBLIC_URL%/icon-192x192.png">

  <!-- For SVG favicons, if you have one -->
  <link rel="icon" type="image/svg+xml" href="%PUBLIC_URL%/favicon.svg">

  <title>Your Awesome React App</title>
</head>

Notice the %PUBLIC_URL% placeholder. Create React App automatically replaces this with the correct path to your public folder during the build process. If you're using Vite or Next.js, you might just use absolute paths like /favicon.ico, as they serve directly from the root.

Step 4: Advanced: Dynamic Favicons with react-helmet

What if you need to change the favicon based on the current route, user role, or even a dynamic status (like a notification count)? This is where React shines, and a library like react-helmet (or react-helmet-async for newer React versions) comes in handy.

First, install it:


npm install react-helmet-async
# or
yarn add react-helmet-async

Then, you can use it in any component to dynamically inject <link> tags into the document's <head>. Let's say you have an admin panel that needs a different favicon:


import React from 'react';
import { Helmet } from 'react-helmet-async';

function AdminDashboard() {
  return (
    <div>
      <Helmet>
        <link rel="icon" type="image/png" href="/admin-favicon.png" />
        <title>Admin Dashboard</title>
      </Helmet>
      <h1>Welcome, Admin!</h1>
      {/* ... rest of your admin content */}
    </div>
  );
}

export default AdminDashboard;

This approach is powerful for multi-tenant applications or dashboards where branding might vary. Just make sure your admin-favicon.png is also in your public folder.

Step 5: Don't Forget the Web App Manifest!

For Progressive Web Apps (PWAs) and Android devices, the manifest.json file is crucial. It defines your app's name, theme colors, and, critically, a set of icons for various contexts (home screen, splash screen, etc.). Mzu favicondl generates this for you.

Ensure your manifest.json is in the public folder and linked in public/index.html as shown in Step 3. You can read more about it in our Web App Manifest Favicon Guide.

Common Pitfalls (Don't Say I Didn't Warn You!)

My Take? Be Thorough.

Honestly, the best react favicon setup is one that covers all bases. Use Mzu favicondl to generate a comprehensive set of icons, place them correctly in your public folder, and link them all in your public/index.html. For dynamic scenarios, react-helmet is your friend.

It might seem like a lot of links and sizes, but it's a small effort for a huge payoff in professionalism and user experience. Your brand deserves to look good everywhere, from a desktop tab to a mobile home screen.