This question has two parts:
- How to add a badge to an icon?
- How to change the favicon dynamically?
I am using NextJS and thus my answer will show how I did it using NextJS. For vanilla React, see for example Dynamically changing favicon in react.js (which doesn't deal with part 1 of the question).
For part 1, I use an SVG favicon that is generated by a JavaScript function which looks something like this:
export const faviconString = (badge?: string | number) => {
let svgFavicon =
'<svg viewBox="0 0 100 100" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">';
svgFavicon +=
'<rect x="0" y="0" width="100%" height="100%" fill="#2196f3" rx="0" ry="0"></rect>';
if (badge) {
svgFavicon += '<circle cx="67" cy="33" r="30" fill="red"></circle>';
svgFavicon +=
'<text font-family="sans-serif" x="68" y="47.7" font-size="3em" fill="white" text-anchor="middle">';
if (
!(typeof badge === 'string' && badge.length > 1) &&
!(typeof badge === 'number' && badge > 9)
) {
svgFavicon += badge;
}
svgFavicon += '</text>';
}
svgFavicon += '</svg>';
const svgFaviconEncoded = Buffer.from(svgFavicon).toString('base64');
const svgFaviconWithPrefix = `data:image/svg+xml;base64,${svgFaviconEncoded}`;
return svgFaviconWithPrefix;
};
The favicon is a blue square. Mine is slightly more complicated but for brevity I reduced it. Note that the SVG is in a string and not an SVG react component or separate SVG file. At the end, it is base64-encoded and the prefix needed to use it as a Data URL is added.
Before the closing SVG tag, some logic is introduced that draws a red circle and, if applicable, a number or a string is drawn on top of that.
For part 2, I use the next/head
component and a regular old useEffect
, something like this:
useEffect(() => {
const newFavicon = faviconString(unreadMessages);
setFavicon(newFavicon);
}, [unreadMessages]);
and in the return statement:
<Head>
<link rel="icon" href={favicon} key="favicon" />
</Head>
If you want an icon that's not an SVG icon, sorry. Good luck!