useFavicon()
Last updated: 24/04/2026
Overview
useFavicon keeps the current favicon path in React state and, on every change, finds or creates a <link rel="…"> in the document head, sets its href to baseUrl + filename, and sets type from the file extension so the browser swaps the tab icon without a full reload. You can point at static assets under a CDN path (baseUrl), match an existing link via rel (for example icon vs shortcut icon), or pass a custom doc when updating a non-default document (tests, embedded HTML). The hook returns a tuple [favicon, setFavicon] like useState, so you can seed an initial icon from newIcon and drive updates from UI or side effects.
What it accepts
- Optional
newIcon- Initial filename or path fragment (joined withbaseUrl). Default''. - Optional
baseUrl- Prefix for the finalhref(for example/icons/or a CDN origin). Default''. - Optional
rel-relselector / attribute for the link node (querySelector('link[rel*="…"]')). Default'icon'. - Optional
doc- TargetDocument(defaultdocument).
What it returns
- A tuple
[favicon, setFavicon]: current icon string and a state setter that triggers a head<link>update on the next commit.
Usage
Example: default vs “busy” favicon under a shared asset prefix, with an explicit rel and document (all options visible).
import useFavicon from '@dedalik/use-react/useFavicon'
function Example() {
const [favicon, setFavicon] = useFavicon({
newIcon: 'favicon.ico',
baseUrl: '/brand/icons/',
rel: 'icon',
doc: document,
})
return (
<div>
<h3>Tab icon</h3>
<p>
Current file: <strong>{favicon || '-'}</strong>
</p>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<button type='button' onClick={() => setFavicon('favicon.ico')}>
Default
</button>
<button type='button' onClick={() => setFavicon('favicon-busy.png')}>
Busy
</button>
</div>
<p style={{ marginTop: 12, opacity: 0.75 }}>
The tab icon updates without a full reload; in devtools → Elements → head, the matching link href becomes{' '}
<code>/brand/icons/</code> plus the filename.
</p>
</div>
)
}
export default function Demo() {
return <Example />
}API Reference
useFavicon
Signature: useFavicon(options?: UseFaviconOptions): UseFaviconReturnType
Parameters
Optional object UseFaviconOptions:
newIcon(string, optional) - Initial icon filename or suffix; combined withbaseUrlforhref. Default''.baseUrl(string, optional) - Prefix prepended tonewIcon. Default''.rel(string, optional) - Used to find/create the<link>(link[rel*="…"]). Default'icon'.doc(Document, optional) - Document whose<head>is updated. Defaultdocument.
Returns
Tuple [favicon, setFavicon] (UseFaviconReturnType):
favicon- Current icon string in state.setFavicon- React state setter; updates state and re-runs the effect that applies the icon.
Copy-paste hook
TypeScript
import React, { useState, useEffect, useCallback } from 'react'
export interface UseFaviconOptions {
newIcon?: string
baseUrl?: string
rel?: string
doc?: Document
}
export type UseFaviconReturnType = [string, React.Dispatch<React.SetStateAction<string>>]
const useFavicon = ({
newIcon = '',
baseUrl = '',
rel = 'icon',
doc = document,
}: UseFaviconOptions = {}): UseFaviconReturnType => {
const [favicon, setFavicon] = useState<string>(newIcon)
const applyIcon = useCallback(
(icon: string) => {
let linkElement = doc.head.querySelector(`link[rel*="${rel}"]`) as HTMLLinkElement
if (!linkElement) {
linkElement = doc.createElement('link')
linkElement.rel = rel
doc.head.appendChild(linkElement)
}
const iconUrl = `${baseUrl}${icon}`
if (linkElement.href !== iconUrl) {
linkElement.href = iconUrl
linkElement.type = `image/${icon.split('.').pop()}`
}
},
[baseUrl, rel, doc],
)
useEffect(() => {
if (typeof favicon === 'string') {
applyIcon(favicon)
}
}, [favicon, applyIcon])
return [favicon, setFavicon]
}
export default useFavicon
export type UseFaviconType = ReturnType<typeof useFavicon>JavaScript
import React, { useState, useEffect, useCallback } from 'react'
const useFavicon = ({ newIcon = '', baseUrl = '', rel = 'icon', doc = document } = {}) => {
const [favicon, setFavicon] = useState(newIcon)
const applyIcon = useCallback(
(icon) => {
let linkElement = doc.head.querySelector(`link[rel*="${rel}"]`)
if (!linkElement) {
linkElement = doc.createElement('link')
linkElement.rel = rel
doc.head.appendChild(linkElement)
}
const iconUrl = `${baseUrl}${icon}`
if (linkElement.href !== iconUrl) {
linkElement.href = iconUrl
linkElement.type = `image/${icon.split('.').pop()}`
}
},
[baseUrl, rel, doc],
)
useEffect(() => {
if (typeof favicon === 'string') {
applyIcon(favicon)
}
}, [favicon, applyIcon])
return [favicon, setFavicon]
}
export default useFavicon