Añadir un favicon a una app de React depende de tu herramienta de compilación: Create React App (CRA) y Vite gestionan los archivos de forma distinta. Esta guía cubre ambos, además de cómo intercambiar favicons en tiempo de ejecución (útil para el modo oscuro o apps de marca blanca).
Create React App (CRA)
CRA pone los archivos estáticos en la carpeta public/.
- Coloca
favicon.icoenpublic/. - Abre
public/index.htmly revisa la etiqueta<link>(CRA incluye una por defecto):
<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%/site.webmanifest" />La variable %PUBLIC_URL% garantiza que la ruta funcione sin importar dónde se despliegue la app (subdirectorio o raíz).
Vite + React
Vite es la opción moderna por defecto para las nuevas apps de React. Los favicons van en public/, pero la plantilla HTML es index.html en la raíz del proyecto (no dentro de public/).
- Coloca tus archivos de favicon en
public/. - Edita el
index.htmlde la raíz y añade etiquetas link en<head>:
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />Vite prefiere los favicons SVG — fíjate en la declaración type="image/svg+xml". Pon tu favicon.svg en public/ y referéncialo con una barra inicial.
Consigue todos los archivos que necesitas (ICO, tamaños PNG, SVG, Apple touch icon, manifest) desde una sola subida en Favicon.one.
Intercambiar el favicon en tiempo de ejecución
Para favicons de modo oscuro o apps de marca blanca, puedes cambiar el favicon dinámicamente con un pequeño hook:
import { useEffect } from 'react'
function useFavicon(href: string) {
useEffect(() => {
let link = document.querySelector("link[rel~='icon']") as HTMLLinkElement
if (!link) {
link = document.createElement('link')
link.rel = 'icon'
document.head.appendChild(link)
}
link.href = href
}, [href])
}
// Usage
function App() {
useFavicon('/favicon-dark.svg')
return <div>...</div>
}Para una configuración completa de modo oscuro (cambio automático), consulta nuestra guía de favicon en modo oscuro.
Usar react-helmet
Si ya usas react-helmet o react-helmet-async para gestionar el <head>, puedes declarar los favicons de forma declarativa:
<Helmet>
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
</Helmet>Next.js vs React (CRA/Vite)
Si usas Next.js, el enfoque es distinto — Next.js tiene convenciones basadas en archivos que generan las etiquetas automáticamente. Consulta nuestra guía de favicon para Next.js.
Problemas comunes con el favicon en React
- Recarga forzada. El servidor de desarrollo de Vite usa la caché de forma agresiva. Detén y reinicia
npm run devsi tu icono no se actualiza. - Carpeta equivocada. Tanto CRA como Vite quieren los archivos en
public/, no ensrc/. - Falta la barra inicial. Usa
/favicon.ico, nofavicon.ico, para que la ruta se resuelva desde la raíz. - El output de la compilación no incluye el archivo. Revisa
dist/(Vite) obuild/(CRA) después de compilar para confirmar que el favicon se copió.
¿Sigues atascado? Consulta la lista de verificación completa de “Favicon Not Showing” (el favicon no aparece).