How can I update class on an element before the website loads (before onMount)?

25 views Asked by At

I added dark mode to my Svelte + Tailwind website. I did this by first checking for the user's preferred (system default) theme, but also added a button to change it anytime. I essentially just update the local storage to either store dark or light and then give or remove the class "dark" from the root html element. I have run into an issue though: I give or remove the "dark" class onMount which means the default light theme flashes for a second (blinding anyone within 10km radius) before it changes to dark theme.

Related code (taken directly from Tailwind dark mode guide):

onMount(() => {
    if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.documentElement.classList.add('dark');
        localStorage.theme = 'dark';
    } else {
        document.documentElement.classList.remove('dark');
        localStorage.theme = 'light';
    }
});

My question(s):

Is there a way to run a function that checks localStorage and applies the "dark" class before displaying the initial website?

If there is no way to do what I am trying to do, is there any other way I can implement themes with the page rendering correctly right away?

3

There are 3 answers

0
brunnerh On BEST ANSWER

onMount only runs fairly late on the client.
You could probably also move the logic to a head script in a layout:

<svelte:head>
  <script>
    ...
  </script>
</svelte:head>

Such scripts should execute about as early as they can (but you cannot use Svelte features there).

0
Petr Hora On

I fixed it by moving the onMount code from the top-most +layout.svelte to a script element in the app.html directly. This removed the light theme from flashing on reload.

0
Kaushikkumar Parmar On

The onMount function typically executes quite late on the client side. Alternatively, you might consider transferring the logic to a head script within a layout:

<svelte:head>
  <script>
    // Your logic here
  </script>
</svelte:head>

These scripts are designed to run as early as feasible, though Svelte features aren't accessible in this context.