Mode Toggle

A Dropdown Menu to toggle between light and dark mode.

Example

Usage

Create the component ~/components/mode-toggle.tsx and paste the following code into it.

import { As } from "@kobalte/core"

import { Icons } from "~/components/icons"
import { Button } from "~/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger
} from "~/components/ui/dropdown-menu"

export function ModeToggle() {
  const setTheme = (theme: string) => {
    localStorage.setItem("theme", theme)
    const root = document.documentElement
    if (theme === "light") {
      root.classList.remove("dark")
    } else {
      root.classList.add("dark")
    }
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <As component={Button} variant="ghost" size="sm" class="w-9 px-0">
          <Icons.sun class="rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
          <Icons.moon class="absolute rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
          <span class="sr-only">Toggle theme</span>
        </As>
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuItem onSelect={() => setTheme("light")}>
          <Icons.sun class="mr-2 h-4 w-4" />
          <span>Light</span>
        </DropdownMenuItem>
        <DropdownMenuItem onSelect={() => setTheme("dark")}>
          <Icons.moon class="mr-2 h-4 w-4" />
          <span>Dark</span>
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

You also need this little script somewhere in the <head /> to load the last selected mode on refresh.

const root = document.documentElement
const theme = localStorage.getItem("theme")
if (theme === "dark") {
  root.classList.add("dark")
} else {
  root.classList.remove("dark")
}