Stop flickering theme after page refresh in Sveltekit and Daisy UI
Tags: sveltekit, svelte, daisyui, tailwindcss
Published: 2023-11-14 09:39:19

   Hi, Sveltian today I would like to share you how to stop theme flickering after we refreshing a page while we using [**Daisy UI**](https://daisyui.com/) with [**Sveltekit**](https://kit.svelte.dev/)

---

## New in Daisy UI 4.0

   Now with Daisy UI 4.0 has been release with new component call [**Theme Controller**](https://daisyui.com/components/theme-controller/) it bring us to a more easier way to change between two theme in Daisy UI , for more info about what change and what new  in Daisy UI 4.0 let check this [**link**](https://daisyui.com/docs/changelog/#400-2023-11-12)

---

## Let see what Theme Controller can do

   Now I expected you has been installing a new Sveltekit project (with a Skeleton Project option selected) 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpj0ym1fz59dgrzyk210.png)

Tailwind CSS and Daisy UI , then we will starting our code

- checking you tailwind.config.js , need to have at least 2 of any themes ([how to setup themes](https://daisyui.com/docs/themes/)) 

> I have set 2 customize theme name '**light**' and '**dark**'

![theme name '**light**' and '**dark**'](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sowec8uu77i8zr65je31.png)

- adding attribute `data-theme` on `html` tag in `src/app.html` page

> for me will set it as '**light**' theme by default while page is loaded

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9orby2z0i0hayriy8xlv.png)



- build svelte component name 'ModeSwitcher' (this name is up to your decide) and in that svelte component put below code into it and using this component on `+layout.svelte`

> I has using  [Theme Controller using a swap component](https://daisyui.com/components/theme-controller/#theme-controller-using-a-swap) from DaisyUI and set it value to 'dark' as it is my dark mode theme name

```
<label class="swap swap-rotate">
	<!-- this hidden checkbox controls the state -->
	<input
		type="checkbox"
		class="theme-controller"
		value="dark"
	/>

	<!-- sun icon -->
	<svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
	</svg>

	<!-- moon icon -->
	<svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
	</svg>
</label>
```

now you can running your dev server and using the that input checkbox (or now it is a sun & moon button) to changing between two themes , for me it will change between theme name '**light**' and '**dark**'

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjterjtsts5wskxtkp0q.gif)


**<u>BUT!!</u>** you will notice that while we reload or refresh the page from a dark theme it will be reloaded back to a default theme that we has been set in `html` tag from previously 

---

## Made theme persistent
firstly I will introduce you to a basically way to persist a theme by using cookie and `onMount` function of svelte if self

let copy a code below and paste it in your current component

```
<script>
	import { onMount } from 'svelte';

	let isDark = false;
	onMount(() => {
		let decodedCookie = decodeURIComponent(document.cookie);
		let ca = decodedCookie.split(';');
		const cookiesObject = ca.map((cookie) => {
		  const [name, value] = cookie.split('=');
		  return { name, value };
		});
	 	const cookieIsDark = cookiesObject.find(cookie=> cookie.name==='isDark');
	 	isDark = JSON.parse(cookieIsDark ? cookieIsDark.value : "false") ;
	});


	function setModeCookie() {
		const expirationDate = new Date();
		expirationDate.setDate(expirationDate.getDate() + 365);
		document.cookie = `isDark=${isDark}; expires=${expirationDate.toUTCString()}`;
	}
</script>

<label class="swap swap-rotate">
	<!-- this hidden checkbox controls the state -->
	<input
		type="checkbox"
		class="theme-controller"
		value="dark"
	/>

	<!-- sun icon -->
	<svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
	</svg>

	<!-- moon icon -->
	<svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
	</svg>
</label>
```
In the code while the component is `onMount` state it will decoding and get a value of cookie name 'isDark' that data type is boolean and will tell us the page currently in dark mode or not and it value will binding with `input` checked state

> for a first time it will be set to false because page didn't have any cookie yet

and after we changing a theme with our theme controller, it will calling `setModeCookie` function that will set a cookie name '**isDark**' with value of our '**isDark**' variable (that suppose to be true by now because we clicked a theme controller and change a page's theme to dark)

now if you try to refresh or reload the page, the theme will be back into a theme that we has been using before we refresh or reload the page

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q7tj7vzvv7svnhtjaxd8.gif)

**<u>BUT AGAIN!!</u>** you will notice some flickering effect after we refresh or reload the page while on 'dark' theme that because the page will be rendered from server side as a 'light' theme and then after 'onMount' is complete the page will get a cookies and set it back to our theme controller to made the page to be in 'dark' theme again  


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4vgaqs9ly51wphgpqrp.png)

---

## Stop theme flickering effect!!!

So far we has been using cookie to set a value that telling us, is currently page is in dark mode or not then in Sveltekit we can accessing that cookie on server side too !! 
then what we need to do is we will calling that cookie in server side and passing it value back to our page and the page will rendered on value of that passing from server side

let create new file in `src` folder and name it `+layout.server.js` and in that file put below code into it

```
/** @type {import('./$types').LayoutServerLoad} */
export async function load({ cookies }) {
    const isDark = cookies.get('isDark') ?? "false";
    return { isDark };
}
```

and put this code below into ModeSwitcher component

```
<script>
	import { page } from '$app/stores';

	let isDark = JSON.parse($page.data.isDark);

	function setModeCookie() {
		const expirationDate = new Date();
		expirationDate.setDate(expirationDate.getDate() + 365);
		document.cookie = `isDark=${isDark}; expires=${expirationDate.toUTCString()};`;
	}
</script>

<label class="swap swap-rotate">
	<!-- this hidden checkbox controls the state -->
	<input
		type="checkbox"
		class="theme-controller"
		value="dark"
	/>

	<!-- sun icon -->
	<svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
	</svg>

	<!-- moon icon -->
	<svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
		<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
	</svg>
</label>
```

then if you see a code in `+layout.server.js` we will try to get a value of cookie with name 'isDark' and if it not exist just passing "false" as a string and made our ModeSwitcher component receiving that value by using 	`import { page } from '$app/stores';` this will get a store of page that we will need to subscribe and call it data by `$page.data.isDark` , last but not less we will set that value back to ModeSwitcher component 's variable name 'isDark' and that variable is got binding on our input checkbox of Theme Controller

that mean while page is rendered, a 'isDark' value will set into a value of our cookie that passing by server side and then it will rendered to correctly theme that suppose to be show in the page with out flickering effect at all