A tale of Favicon’s and React

Cameron Bourke
4 min readJun 2, 2016

--

Recently I was aimed with the simple looking task of adding favicons to a fairly large react app. The end result was an enduring battle against the browser cache, IE, Edge and meta tags. I haven’t lost you yet? Awesome, let’s begin.

What’s the Deal with Favicon Sizes?

Before I could add any favicons to the app, I needed to read up on which favicons where rquired, and why. One of the best resources that I came across that really spelled it out for me was the FAQ page at the realfavicongenerator (which also can check that the favicons are correct on your site after you’ve added them). It does a good job of listing each favicon in use today and for which platform, but more importantly why that size or type is needed.

The Current Landscape in React

Once I knew I had all the favicon sizes that I needed, I discovered a really nice npm package for dealing and managing the head of your document in react, developed by the engineering team at the nfl, which is ironically named react-helmet. Initially I used react-helmet to append all the link tags for the favicons into the head. Life was good, because I could simply “require” the file, and let webpack base64 encode and inline the icon, which meant no need to make a request to load the favicon. This would also help mitigate the impact of a bug in chrome where it requests and downloads all the <links> with the attribute “rel=icon” and then chooses the appropriate size. However, IE does not support inline base64 for href’s, and it made little sense to continually let react diff these link elements when the url for each favicon was constant.

This lives in the root component, which in my case was <App />

Back to the Good Ol’ Days

Instead of using react-helmet to append the favicon links in the head, I now only use it to initially append and then update any dynamic content that lives in the head. Which meant adding some plain old <link> tags in the head of the index.html was in order (shown above). Lastly, I used webpack to copy all the favicon images into the root of the build folder (the browser by default will look for favicon’s in the root).

This got things working in IE11 and Edge, until it didn’t…

React Router & history.pushState

Almost every complex react app uses react-router to keep the url and components in sync. However, under the hood react-router uses the History API in the browser and more importantly the pushState method which causes a bug in both IE and Edge where the favicon disappears when navigating to a new route (which by the way currently has the status of won’t fix). This meant getting creative, and luckily a fix popped up that works for Edge, but unfortunately not for IE. The fix is pretty simple, you simply reassign the link’s href using the onUpdate method on the <Router /> component.

This meant getting creative, and luckily a fix popped up that works for Edge, but unfortunately not for IE

But… What if the Favicon Needs to Change?

There is nothing stopping a requirement for the favicon to be updated for the app tomorrow, or the next day. Browsers love to cache these little guys, and so relying on the browser to respond to the newest favicon when available is unreliable. One handy little trick that forces the browser to fetch the favicon again is to add a query parameter to the url. The convention is to use a “v”, that stands for version number, and have it equal the current version of the favicon being used.

<link ... href="/favicon-16x16.png?v=2">

And Lastly, Adding the Polish

  • Adding the “apple-mobile-web-app-title” <meta> tag for iOS allows you to set the default name for the icon if the user adds the site to their home screen.
<Helmet
titleTemplate={“%s | “ + config.siteName}
meta={[{
name: ‘apple-mobile-web-app-title’,
content: config.appName,
}, {

}]}
/>
  • Currently, the “manifest.json” is used by chrome when creating browser extensions, but it is also used by android chrome to specify (like you can for iOS above) the default name for the icon when the user adds the site to the their home screen.
{
// note: make sure the version is 2 in order
// for the manifest to take effect currently
“manifest_version”: 2,
“name”: “Your App Name”,
“icons”: [{
“src”: “\/android-chrome-36x36.png”,
“sizes”: “36x36”,
“type”: “image\/png”,
“density”: 0.75
}, {
...
}]
}
  • If you need to add tiles for Windows, and only need to support IE11 or newer, than “browserconfig.xml” is your friend. Instead of having to add more <link> tags to your head, Windows will look in the root of your directory for this config, and then use the references within this file to find your tile images.

--

--