How to add dark mode for phoenix 1.7?

Hello,

I am new to TailwindCSS and try to add a dark mode to a freshly generated phoenix app.

From Dark Mode - Tailwind CSS I learned

  • to add darkMode: 'class' to my tailwind.config.js,
  • to add class="dark" to the html-tag, and
  • to put dark: in front of any color, like so dark:bg-black

That works so far, but the user is not able to switch between dark and normal mode yet. Is there a way to remove/add class="dark" from/to the html-tag on server side in pure elixir with Lieview or has this to be done via JS?

For now, I have added "dark" to the <html> tag by LiveView JS hook

That’s what I’ve been using on my website:

// app.js
function darkExpected() {
  return localStorage.theme === 'dark' || (!('theme' in localStorage) &&
    window.matchMedia('(prefers-color-scheme: dark)').matches);
}

function initDarkMode() {
  // On page load or when changing themes, best to add inline in `head` to avoid FOUC
  if (darkExpected()) document.documentElement.classList.add('dark');
  else document.documentElement.classList.remove('dark');
}

window.addEventListener("toogle-darkmode", e => {
  if (darkExpected()) localStorage.theme = 'light';
  else localStorage.theme = 'dark';
  initDarkMode();
})

initDarkMode();

// trigger
// phx-click={JS.dispatch("toogle-darkmode")}
8 Likes

You can use ETS to set up the initial value in the application

#start the ets lookup table
:ets.new(:my_ets, [:named_table, {:read_concurrency, true}])

#set theme_mode default
:ets.insert(:my_ets, {"theme_mode", :light})  
## true

add your toggle button

##toggle button
<button phx-click="toggle_mode">Toggle theme</button>

Monitor the click event

def handle_event("toggle_mode", _params, socket) do  
   toggle_theme_mode(socket)
   |> then( fn mode ->
   {:reply, %{mode: mode}, socket} end)

#toggle theme mode
defp toggle_theme_mode(socket) do
   case socket.assigns.theme_mode do
       :dark  -> assign(socket, :theme_mode, :light)
       :light  -> assign(socket, :theme_mode, :dark)
   end
end

include class={@theme_mode} in your template.