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 install 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 "svelte-radix/Sun.svelte" ;
import Moon from "svelte-radix/Moon.svelte" ;
import { toggleMode } from "mode-watcher" ;
import { Button } from "$lib/components/ui/button/index.js" ;
</ script >
< Button on: click ={ 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 on: click ={ 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 "svelte-radix/Sun.svelte" ;
import Moon from "svelte-radix/Moon.svelte" ;
import { resetMode , setMode } from "mode-watcher" ;
import { Button } from "$lib/components/ui/button/index.js" ;
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js" ;
</ script >
< DropdownMenu.Root >
< DropdownMenu.Trigger asChild let: builder >
< Button builders ={[ builder ]} 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 >
</ DropdownMenu.Trigger >
< DropdownMenu.Content align = "end" >
< DropdownMenu.Item on: click ={() => setMode ( "light" )}
> Light </ DropdownMenu.Item
>
< DropdownMenu.Item on: click ={() => setMode ( "dark" )}> Dark </ DropdownMenu.Item >
< DropdownMenu.Item on: click ={() => 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 { Button } from "$lib/components/ui/button/index.js" ;
</ script >
< DropdownMenu.Root >
< DropdownMenu.Trigger asChild let: builder >
< Button builders ={[ builder ]} 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 >
</ DropdownMenu.Trigger >
< DropdownMenu.Content align = "end" >
< DropdownMenu.Item on: click ={() => setMode ( "light" )}
> Light </ DropdownMenu.Item
>
< DropdownMenu.Item on: click ={() => setMode ( "dark" )}> Dark </ DropdownMenu.Item >
< DropdownMenu.Item on: click ={() => 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