LiveView components and app level configuration

Hey,

We have a collection of about 50 live_components that we are migrating to function components (for most of them) and to HEEX templating.

Our components are used within different applications and can be themed according to application-level configuration. Our former live_components used to fetch the theme according the application name defined in the socket.

But function components no longer have access to the socket, and we don’t want to explicitly pass the theme as an assign in every template, we want something less obtrusive.

We already found a workaround when using new function components from LEEX templates: we wrote our own component macro that un-hygienically injects the theme in assigns.

We are wondering what would be the best unobtrusive way to inject theme when using function components in HEEX templates : <.my_component_that_require_a_theme_assign ... />

Inject or wrap so you request the theme if it’s not assigned?

def render(assigns) do
  assigns = assign_new(:theme, fn -> get_theme() end)
~H""

The issue is that the get_theme function doesn’t have enough context to get the theme.

In my live_components the get_theme function take the socket as a parameter (used to get the current phoenix application name, which is then used to fetch the proper application theme)

I finally managed to find a work-around: the theme is set at the router level using a pre_mount hook in a Registry. Using a Registry makes the theme bound to a specific PID (liveview’s PID)

Then any component that needs the theme can fetch it from the registry (since all components are running within the liveview’s process and hence share the same PID)

The hook:

defmodule ThemeHook do
  
  def on_mount(:default, _params, _session, socket) do
    theme = socket |> app_name() |> ThemeHelpers.application_theme()
    Registry.register(ThemeRegistry, :theme, theme)
    {:cont, socket}
  end
  
end

used from the router

live_session :default, on_mount: ThemeHook do
   ...
end