Specifying Favicon for standalone HTML

It is a small detail, but setting the favicon feels like it contributes a lot to having a professional looking app. As it stands now the only way that I am aware of to set the favicon is by setting the parameter in a template. Since I am exporting the app to a standalone HTML and templates are not yet supported for this I need to find another option.

There is the --ico-path option to use when launching an app from a bokeh server, but I have not gotten this to work and I do not think it would carry the path over to a standalone file as well.

--ico-path ICO_PATH Path to a .ico file to use as the favicon.ico, or 'none' to disable favicon.ico support. If unset, a default Bokeh .ico file will be used

Is there another work around? Can I change the default path for the HTML from the one below?

Thank you for any possible help!

1 Like

You can use js, though the challenge with this is, it briefly flashes the panel favicon before loading your favicon. Please note that this is assuming that your static_dirs folder is assets

import panel as pn

pn.extension()

FAVICON_PATH = "assets/favicon.ico"

def enforce_favicon():
    html = f"""
    <script>
      // Function to set your favicon and remove defaults
      function setFavicon() {{
        // Remove all existing favicon links
        document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"]').forEach(e => e.remove());
        // Create new link tag for your favicon
        const link = document.createElement('link');
        link.rel = 'icon';
        link.href = '{FAVICON_PATH}';
        document.head.appendChild(link);
      }}

      // Immediately attempt to set favicon (for preload)
      setFavicon();

      // Observe head for any favicon changes (Panel sometimes re-adds its own)
      const observer = new MutationObserver((mutations) => {{
        const hasPanelFavicon = Array.from(document.querySelectorAll('link[rel="icon"]'))
          .some(l => l.href.includes('panel'));
        if (hasPanelFavicon) {{
          setFavicon();
        }}
      }});
      observer.observe(document.head, {{ childList: true, subtree: true }});

      // Also run once after full DOM load
      window.addEventListener('load', setFavicon);
    </script>
    """
    return pn.pane.HTML(html, width=0, height=0, margin=0, sizing_mode="fixed")

# --- Example dashboard ---
dashboard = pn.Column(
    enforce_favicon(),
    pn.pane.Markdown("## 🦊 Your favicon is locked — no flash, no revert."),
    pn.Spacer(height=400),
)

dashboard.servable()