Changing website favicon dynamically

Viewed 263528

I have a web application that's branded according to the user that's currently logged in. I'd like to change the favicon of the page to be the logo of the private label, but I'm unable to find any code or any examples of how to do this. Has anybody successfully done this before?

I'm picturing having a dozen icons in a folder, and the reference to which favicon.ico file to use is just generated dynamically along with the HTML page. Thoughts?

18 Answers

Why not?

var link = document.querySelector("link[rel~='icon']");
if (!link) {
    link = document.createElement('link');
    link.rel = 'icon';
    document.getElementsByTagName('head')[0].appendChild(link);
}
link.href = 'https://stackoverflow.com/favicon.ico';

If you have the following HTML snippet:

<link id="favicon" rel="shortcut icon" type="image/png" href="favicon.png" />

You can change the favicon using Javascript by changing the HREF element on this link, for instance (assuming you're using JQuery):

$("#favicon").attr("href","favicon2.png");

You can also create a Canvas element and set the HREF as a ToDataURL() of the canvas, much like the Favicon Defender does.

Here's a snippet to make the favicon be an emoji, or text. It works in the console when I'm at stackoverflow.

function changeFavicon(text) {
  const canvas = document.createElement('canvas');
  canvas.height = 64;
  canvas.width = 64;
  const ctx = canvas.getContext('2d');
  ctx.font = '64px serif';
  ctx.fillText(text, 0, 64);

  const link = document.createElement('link');
  const oldLinks = document.querySelectorAll('link[rel="shortcut icon"]');
  oldLinks.forEach(e => e.parentNode.removeChild(e));
  link.id = 'dynamic-favicon';
  link.rel = 'shortcut icon';
  link.href = canvas.toDataURL();
  document.head.appendChild(link);
}

changeFavicon('❤️');

The favicon is declared in the head tag with something like:

<link rel="shortcut icon" type="image/ico" href="favicon.ico">

You should be able to just pass the name of the icon you want along in the view data and throw it into the head tag.

Or if you want an emoticon :)

var canvas = document.createElement("canvas");
canvas.height = 64;
canvas.width = 64;

var ctx = canvas.getContext("2d");
ctx.font = "64px serif";
ctx.fillText("☠️", 0, 64); 

$("link[rel*='icon']").prop("href", canvas.toDataURL());

Props to https://koddsson.com/posts/emoji-favicon/

The only way to make this work for IE is to set you web server to treat requests for *.ico to call your server side scripting language (PHP, .NET, etc). Also setup *.ico to redirect to a single script and have this script deliver the correct favicon file. I'm sure there is still going to be some interesting issues with cache if you want to be able to bounce back and forth in the same browser between different favicons.

There is a single line solution for those who use jQuery:

$("link[rel*='icon']").prop("href",'https://www.stackoverflow.com/favicon.ico');

I use this feature all the time when developing sites ... so I can see at-a-glance which tab has local, dev or prod running in it.

Now that Chrome supports SVG favicons it makes it a whole lot easier.

Tampermonkey Script

Have a gander at https://gist.github.com/elliz/bb7661d8ed1535c93d03afcd0609360f for a tampermonkey script that points to a demo site I chucked up at https://elliz.github.io/svg-favicon/

Basic code

Adapted this from another answer ... could be improved but good enough for my needs.

(function() {
    'use strict';

    // play with https://codepen.io/elliz/full/ygvgay for getting it right
    // viewBox is required but does not need to be 16x16
    const svg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
      <circle cx="8" cy="8" r="7.2" fill="gold" stroke="#000" stroke-width="1" />
      <circle cx="8" cy="8" r="3.1" fill="#fff" stroke="#000" stroke-width="1" />
    </svg>
    `;

    var favicon_link_html = document.createElement('link');
    favicon_link_html.rel = 'icon';
    favicon_link_html.href = svgToDataUri(svg);
    favicon_link_html.type = 'image/svg+xml';

    try {
        let favicons = document.querySelectorAll('link[rel~="icon"]');
        favicons.forEach(function(favicon) {
            favicon.parentNode.removeChild(favicon);
        });

        const head = document.getElementsByTagName('head')[0];
        head.insertBefore( favicon_link_html, head.firstChild );
    }
    catch(e) { }

    // functions -------------------------------
    function escapeRegExp(str) {
        return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
    }

    function replaceAll(str, find, replace) {
        return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
    }

    function svgToDataUri(svg) {
        // these may not all be needed - used to be for uri-encoded svg in old browsers
        var encoded = svg.replace(/\s+/g, " ")
        encoded = replaceAll(encoded, "%", "%25");
        encoded = replaceAll(encoded, "> <", "><"); // normalise spaces elements
        encoded = replaceAll(encoded, "; }", ";}"); // normalise spaces css
        encoded = replaceAll(encoded, "<", "%3c");
        encoded = replaceAll(encoded, ">", "%3e");
        encoded = replaceAll(encoded, "\"", "'"); // normalise quotes ... possible issues with quotes in <text>
        encoded = replaceAll(encoded, "#", "%23"); // needed for ie and firefox
        encoded = replaceAll(encoded, "{", "%7b");
        encoded = replaceAll(encoded, "}", "%7d");
        encoded = replaceAll(encoded, "|", "%7c");
        encoded = replaceAll(encoded, "^", "%5e");
        encoded = replaceAll(encoded, "`", "%60");
        encoded = replaceAll(encoded, "@", "%40");
        var dataUri = 'data:image/svg+xml;charset=UTF-8,' + encoded.trim();
        return dataUri;
    }

})();

Just pop your own SVG (maybe cleaned with Jake Archibald's SVGOMG if you're using a tool) into the const at the top. Make sure it is square (using the viewBox attribute) and you're good to go.

in most cases, favicon is declared like this.

<link rel="icon" href"...." />

This way you can attain reference to it with this.

const linkElement = document.querySelector('link[rel=icon]');

and you can change the picture with this

linkElement.href = 'url/to/any/picture/remote/or/relative';

According to WikiPedia, you can specify which favicon file to load using the link tag in the head section, with a parameter of rel="icon".

For example:

 <link rel="icon" type="image/png" href="/path/image.png">

I imagine if you wanted to write some dynamic content for that call, you would have access to cookies so you could retrieve your session information that way and present appropriate content.

You may fall foul of file formats (IE reportedly only supports it's .ICO format, whilst most everyone else supports PNG and GIF images) and possibly caching issues, both on the browser and through proxies. This would be because of the original itention of favicon, specifically, for marking a bookmark with a site's mini-logo.

Testing the proposed solutions on 2021 on Chrome, I found that some times the browser cache the favicon and do not show the change, even if the link was changed

This code worked (similar to previous proposal but adds a random parameter to avoid caching)

let oldFavicon = document.getElementById('favicon')
var link = document.createElement('link')
link.id = 'favicon';
link.type = 'image/x-icon'
link.rel = 'icon';
link.href = new_favicon_url +'?=' + Math.random();
if (oldFavicon) {
    document.head.removeChild(oldFavicon);
}
document.head.appendChild(link);

Copied from https://gist.github.com/mathiasbynens/428626#gistcomment-1809869 in case that someone else have the same problem

Related