LiveView Dynamic Favicon?

In my LiveView app, I use live_title_tag to generate a dynamic browser title. Works great!

I’d also like to have a dynamic favicon but haven’t been able to get that working.

In my helper module MyWeb.LiveHelpers I put a function component:

def favicon_tag(assigns) do
  color = assigns[:color] || "black"
  href="/img/favicon-#{color}.ico"
  ~H"""
  <link rel="icon" type="image/x-icon" href={href} size="32x32"/>
  """
end

In my layout/root_live.html.heex I add the tag:

<MyWeb.LiveHelpers.favicon_tag color={assigns[:color]} />

The function component is called once when the page first loads, but is not re-run when I change the value of the color attribute.

Should this work? Can I update the favicon dynamically with LiveView, or do I have to fall back to Javascript?

1 Like

The root layout is rendered once so is ‘static’. Any dynamic content (LiveView) is rendered inside that static container.

The title is a special case with special handlers in the Phoenix LiveView JS to allow the title in the browser to match the page.

The link element may be placed inside the body element (not root_live), depending on the type. You can check if a favicon link is allowed, but I highly doubt it.

1 Like

But what you can do is manipulating the DOM with Javascript.

Maybe the examples given in that post might be reason to include such functionality in Phoenix LiveView JS. It seems quite useful to be dynamic.
You could try and post a feature request!

1 Like
1 Like

@BartOtten thanks for the info and links. Here’s the solution I used…

First, have a collection of favicon images that follow a regular file naming convention.

/priv/images/favicon-black.ico
/priv/images/favicon-blue.ico
/priv/images/favicon-red.ico
/priv/images/favicon-green.ico

In layouts/root_live.html.heex, put a favicon tag in your head section.

<link id="favicon" rel="icon" type="image/x-icon" href="/images/favicon-black.ico"/>

Add an event listener in app.js

window.addEventListener("phx:newfav", (e) => {
  var color = e.detail.color 
  var fabtag = document.getElementById('favicon') 
  fabtag.href = `/images/favicon-${color}.ico`
}) 

Then add an event handler to mypage_live.ex

def handle_info({"newfav", newcolor}, socket) do 
  {:noreply, push_event(socket, "newfav", %{color: newcolor})}
end

When it’s time to update the favicon, send a message to your LiveView:

send(self(), {"newfav", "blue"})

Dynamic favicons are super handy for notices and status indicators!

An automagic live_favicon_tag function would be ideal, but this approach seems workable.

1 Like