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()