BartOtten

BartOtten

Proposal

  • Support DOM patching of the HTML link element for a favicon.
  • Add the special @page_favicon assign mimicking the @page_title assign so each page can have it’s own dynamic favicon; supporting multiple tabs for an application with different ‘statuses’.

Reason
Many modern web applications have dynamic favicons. These dynamic favicons are used to notify browser users of events or statuses. For example: unread messages or a CI build status. As those use cases are quite common, providing such functionality seems to fit the ‘no Javascript’-philosophy. Additionaly it seems to align with the automagic @page_title.

Because the root layout from the Plug pipeline is rendered outside of LiveView, the contents cannot be dynamically changed. The one exception is the <title> of the HTML document. Phoenix LiveView special cases the @page_title assign to allow dynamically updating the title of the page, which is useful when using live navigation, or annotating the browser tab with a notification. For example, to update the user’s notification count in the browser’s title bar, first set the page_title assign on mount
Live layouts — Phoenix LiveView v1.2.5

Current State

  • The HTML link element for favicons is placed in layout/root_live.html.heex. No native logic is in place to update it in the DOM and there is no @page_favicon.
  • The HTML title element is placed in `layout/root_live.html.heex. Native logic is in place to update the element in the DOM when the @page_title assignment is changed.

Todo

  • get approval for feature
  • research possibilities
  • draft design
  • get approval for design
  • implement

I am willing to work on this as contribution to the community.

Links
[LiveView Dynamic Favicon?]
[https://medium.com/@alperen.talaslioglu/building-dynamic-favicon-with-javascript-223ad7999661]

First 10 of 22 Posts Switch mode

AndyL

AndyL

Here is a working prototype for Dynamic Favicon. A streamlined solution that follows the style of live_title_tag would be great. I will help. :wink:

AndyL

AndyL

Here’s some rough design ideas:

Let there be a special assign @favicon_href

The live_favicon_tag would go into layout/root_live.html.heex

<%= live_favicon_tag assigns[:favicon_href] || "/images/favicon.ico" %>

The live_favicon_tag function would emit the following HTML

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

Add an event listener to the client javascript

window.addEventListener("phx:change-favicon", (e) => {
  var href = e.detail.href 
  var fabtag = document.getElementById('phx-favicon') 
  fabtag.href = href
})

On the server, when the LiveView process detects that @favicon_href has changed, push an event to the client:

push_event(socket, "change-favicon", %{href: @favicon_href})}

With this approach, add-on packages (like live_dashboard) could add their own favicon images to priv/images, and then use their own favicons in their particular LiveViews.

10
Post #2
josevalim

josevalim

Creator of Elixir

Awesome job @AndyL! I am not sure if this is such a common use case to warrant inclusion on LiveView, but that’s all the pieces needed for anyone who wants to roll with it. :slight_smile:

PJextra

PJextra

It would be a great quick win!

BartOtten

BartOtten OP

Great example!

  • Should it support a size opt (or list of sizes and return multiple elements)?
  • SVG icons can be styled with CSS; removing the need for multiple images (in an ico container). Should it support that use case and if so, how? Blog post: Building an adaptive favicon

The other option is to keep is really simple and let a lib handle more advanced usecases :slight_smile:

AndyL

AndyL

Didn’t know about SVG icons - super nice! Pretty well supported on desktop browsers, less on mobile. Also learned that people sometimes use multiple favicon links, to give browsers an way to fall back to supported types.

I think there are two alternatives to attack this problem: manual coding like I did in the prototype, or editing LiveView itself. I don’t think this can be done with a Library, because there is no way for a Library to inject behavior into the LiveView JS. Is this right?

I looked in the LiveView code to understand live_title_tag - there seems to be three key areas in the code:

The code itself looks pretty straightforward - with a good amount of testing support.

Generating the appropriate favicon mime type could be done by checking the file extension of the href - this could be done in the javascript.

size opt

I’m not sure what the size opt does - I’ve always used ‘auto’ size.

The other option is to keep is really simple

If we could do something simple to streamline the 80% case, people could always fall back to a manual approach if needed.

BartOtten

BartOtten OP

Chose to keep the assign key generic; not sure of we can pass components to it (its too late).

If we can the favicon_tag function can use the (to be updated) DOM diffing too as no attribute is in the name. This allow for the simple approach by default using it as href when assigned a binary. Keeping the advanced usage of favicons to a lib which can simply pass a full icon link element. :slight_smile:

Too be continued….first let’s see if the draft PR survives the public exposure.

https://github.com/phoenixframework/phoenix_live_view/pull/2087

Won’t take long before you can play Doom in the browsers` tab bar…

AndyL

AndyL

PR looks great - beautiful screen shot!

I’m curious - did you intend that it should be possible to update multiple favicon links, or just one? If multiple: would you assign an array of hrefs to @favicon, or use some other convention?

BartOtten

BartOtten OP

Last night I looked at support for multiple icons

Phoenix LiveView is awesome at diffing and sending the least amount of data over the wire. I am trying to keep that in honor. As a result I have chosen to use a simple string replace.

The free schema also makes it easier to use online favicon generators that generate a bunch of PNG files for you. Just unzip and place in a subfolder of a variant. SVG scale so don’t need a subfolder. See pseudo code:

# pseudo code supports multiple schema’s
<.live_favicon href="/images/svg/@dynamic.svg" />
<.live_favicon href="/images/status/@dynamic/favicon-32x32.png" />
<.live_favicon href="/images/status/@dynamic/favicon-16x16.png" />

When a new @dynamic value is assigned, the href is split in 3 parts: prefix, @dynamic and suffix. The dynamic value is replaced with the value assigned.

static: /images/status/
dynamic: “new_message”
static: /favicon-32x32.png

Only the dynamic part is sent over the wire on socket assign updates. Just like…LiveView does already :slight_smile:

{"f": {   "dynamic": "new_message"}}

When href is defined without a dynamic, the helper assumes the user needs full control over the href and just passes it through. Thus supporting base64 encoded data and one-off use cases.

This also allow me to add ‘class’ to support those fancy dynamic SVG’s.

As you like screenshots:

BartOtten

BartOtten OP

Update: the draft PR is rejected

Not sure if the presented solution really covers the use cases as mentioned above. It does cover the simple first case in the draft though, so it’s not a surprise. Will check later.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement