Theming components
View SourceTheming Strategies
The storybook gives you different possibilities to apply a theme to your components. These possibilities are named strategies.
The following strategies are available:
- sandbox class: set your theme as a CSS class, on the sandbox container, with a custom prefix
 - assign: pass the theme as an assign to your components, with a custom key.
 - function: call a custom module/function along with the current theme.
 
Here is how you can use these strategies. In your storybook.ex:
use PhoenixStorybook,
  themes_strategies: [
    sandbox_class: "prefix", # will set a class prefixed by `prefix-` on the sandbox container
    assign: :theme,
    function: {MyApp.ThemeHelper, :register_theme}
  ]If the themes_strategies key is undefined, the default sandbox_class: "theme" strategy is applied.
CSS theming
By default, the storybook is applying a theme-* CSS class to your components/page containers and
you should do as well to your application HTML body element.
It will allow you to style raw HTML elements
body.theme-colorful {
  font-family: // ...
}
.theme-colorful h1 {
  font-family: // ...
  font-size: // ...
}Using a Registry
This chapter explain how you can leverage on a Registry with the function theming strategy.
An effective way to store the current theme setting so that it can be available to all your components, but still have different values for different (concurrent) users is to associate it to the current LiveView pid.
Registry is a native Elixir module that handles decentralized storage, linked to specific
processes. We will leverage on this to associate a theme to the current LiveView pid.
First start a Registry from your Application module.
defmodule PhenixStorybook.Application do
  def start(_type, _args) do
    children = [
      {Registry, keys: :duplicate, name: ThemeRegistry}
    ]
  end
endThen create a LiveView Hook that will fetch the theme from wherever it is relevant for your
application: database, user session, URL params... and store it in the Registry (it's working
because the Hook is running under the same pid than the LiveView).
defmodule ThemeHook do
  def on_mount(:default, params, _session, socket) do
    theme = current_user_theme(socket, params)
    Registry.register(ThemeRegistry, :theme, theme)
    {:cont, socket}
  end
endMount the hook in your router.
defmodule Router do
  live_session :default, on_mount: [ThemeHook] do
    scope "/" do
      # ...
    end
  end
endWrite a helper module, to be used from your components to fetch the current theme from the
Registry and merge it in the component's assigns.
defmodule ThemeHelpers do
  def set_theme(assigns) do
    pid_and_themes = Registry.lookup(ThemeRegistry, :theme)
    case find_by_pid(pid_and_themes, self()) do
      {_pid, theme} -> Map.put_new(assigns, :theme, theme)
      _ -> raise("theme not found in registry")
    end
  end
  defp find_by_pid(pid_and_themes, current_pid) do
    Enum.find(pid_and_themes, fn {pid, _} -> pid == current_pid end)
  end
end