Create an inline theme script This script will, in part, keep and track the dark mode value in localStorage
and prevent FUOC .
src/pages/index.astro
---
import "$lib/styles/app.css" ;
---
< script is:inline >
const isBrowser = typeof localStorage !== 'undefined' ;
const getThemePreference = () => {
if (isBrowser && localStorage. getItem ( 'theme' )) {
return localStorage. getItem ( 'theme' );
}
return window. matchMedia ( '(prefers-color-scheme: dark)' ).matches
? 'dark' : 'light' ;
};
const isDark = getThemePreference () === 'dark' ;
document.documentElement.classList[isDark ? 'add' : 'remove' ]( 'dark' );
if (isBrowser) {
const observer = new MutationObserver (() => {
const isDark = document.documentElement.classList. contains ( 'dark' );
localStorage. setItem ( 'theme' , isDark ? 'dark' : 'light' );
});
observer. observe (document.documentElement, {
attributes: true ,
attributeFilter: [ 'class' ]
});
}
</ script >
< html lang = "en" >
< body >
< h1 >Astro</ h1 >
</ body >
</ html >
</ script >
Copy Install mode-watcher
npm i mode-watcher
select package manager npm Copy Add the ModeWatcher component Import the ModeWatcher
component and use it in your page with the client:load
directive:
src/pages/index.astro
---
import "$lib/styles/app.css" ;
import { ModeWatcher } from "mode-watcher" ;
---
<!-- inline-script -->
< html lang = "en" >
< body >
< h1 >Astro</ h1 >
< ModeWatcher client:load />
</ body >
</ html >
Copy Create a mode toggle Create a mode toggle on your site to toggle between light and dark mode:
Light switch
< script lang = "ts" >
import Sun from "lucide-svelte/icons/sun" ;
import Moon from "lucide-svelte/icons/moon" ;
import { toggleMode } from "mode-watcher" ;
import { Button } from "$lib/components/ui/button/index.js" ;
</ script >
< Button onclick ={toggleMode} variant = "outline" size = "icon" >
< Sun
class = "h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
< Moon
class = "absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
< span class = "sr-only" >Toggle theme</ span >
</ Button >
Copy
< script lang = "ts" >
import Sun from "lucide-svelte/icons/sun" ;
import Moon from "lucide-svelte/icons/moon" ;
import { toggleMode } from "mode-watcher" ;
import { Button } from "$lib/components/ui/button/index.js" ;
</ script >
< Button onclick ={toggleMode} variant = "outline" size = "icon" >
< Sun
class = "h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
< Moon
class = "absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
< span class = "sr-only" >Toggle theme</ span >
</ Button >
Copy
< script lang = "ts" >
import Sun from "lucide-svelte/icons/sun" ;
import Moon from "lucide-svelte/icons/moon" ;
import { resetMode, setMode } from "mode-watcher" ;
import { buttonVariants } from "$lib/components/ui/button/index.js" ;
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js" ;
</ script >
< DropdownMenu . Root >
< DropdownMenu . Trigger
class ={ buttonVariants ({ variant: "outline" , size: "icon" })}
>
< Sun
class = "h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
< Moon
class = "absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
< span class = "sr-only" >Toggle theme</ span >
</ DropdownMenu . Trigger >
< DropdownMenu . Content align = "end" >
< DropdownMenu . Item onclick ={() => setMode ( "light" )}>Light</ DropdownMenu . Item
>
< DropdownMenu . Item onclick ={() => setMode ( "dark" )}>Dark</ DropdownMenu . Item >
< DropdownMenu . Item onclick ={() => resetMode ()}>System</ DropdownMenu . Item >
</ DropdownMenu . Content >
</ DropdownMenu . Root >
Copy
< script lang = "ts" >
import Sun from "lucide-svelte/icons/sun" ;
import Moon from "lucide-svelte/icons/moon" ;
import { resetMode, setMode } from "mode-watcher" ;
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js" ;
import { buttonVariants } from "$lib/components/ui/button/index.js" ;
</ script >
< DropdownMenu . Root >
< DropdownMenu . Trigger
class ={ buttonVariants ({ variant: "outline" , size: "icon" })}
>
< Sun
class = "h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
< Moon
class = "absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
< span class = "sr-only" >Toggle theme</ span >
</ DropdownMenu . Trigger >
< DropdownMenu . Content align = "end" >
< DropdownMenu . Item onclick ={() => setMode ( "light" )}>Light</ DropdownMenu . Item
>
< DropdownMenu . Item onclick ={() => setMode ( "dark" )}>Dark</ DropdownMenu . Item >
< DropdownMenu . Item onclick ={() => resetMode ()}>System</ DropdownMenu . Item >
</ DropdownMenu . Content >
</ DropdownMenu . Root >
Copy
Add mode toggle to page Add the mode toggle to the page (also with the client:load
directive):
src/pages/index.astro
---
import "$lib/styles/app.css" ;
import { ModeWatcher } from "mode-watcher" ;
import ModeToggle from "$lib/components/mode-toggle.svelte" ;
---
<!-- inline-script -->
< html lang = "en" >
< body >
< h1 >Astro</ h1 >
< ModeWatcher client:load />
< ModeToggle client:load />
</ body >
</ html >
Copy