KitlenoKitlenov2.0.0

Actions & display / Light and Dark Mode

Light and Dark Mode

Light and dark mode components are used to toggle between different visual themes in an application, improving usability and accessibility in different lighting conditions.

Light and Dark Mode

Sun

Add this line to your global CSS file (e.g. globals.css) — it's a one-time setup step, not part of the component below.

@custom-variant dark (&:where(.dark, .dark *));
components/ThemeToggle.js
'use client'
    
import { useEffect, useState } from 'react'
import Image from 'next/image'
    
export default function ThemeToggle() {
  const [theme, setTheme] = useState('light')

  useEffect(() => {
    const saved = localStorage.getItem('theme')
    
    if (saved) {
      setTheme(saved)
      document.documentElement.classList.toggle('dark', saved === 'dark')
    } else {
      const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
      const initial = systemDark ? 'dark' : 'light'
    
      setTheme(initial)
      document.documentElement.classList.toggle('dark', systemDark)
    }
  }, [])
    
  const toggleTheme = () => {
    const newTheme = theme === 'dark' ? 'light' : 'dark'
    
    setTheme(newTheme)
    localStorage.setItem('theme', newTheme)
    
    document.documentElement.classList.toggle('dark', newTheme === 'dark')
  }
    
  return (
    <div
      onClick={toggleTheme}
      className="relative w-16 h-8 flex items-center bg-[#ffffff] dark:bg-[#2a2a2a] border-2 border-[#e8e8e8] dark:border-[#4c4c4c] rounded-full cursor-pointer transition-colors duration-300">
      <div className={'absolute left-1 transition-transform duration-300 ease-in-out ' + (theme === 'dark' ? 'translate-x-6' : '')}>
        <div className="w-8 h-6 flex items-center justify-center rounded-full">
          {theme === 'light' ? (
            <Image src="/icons/sun.svg" alt="Sun" width={20} height={20} />
          ) : (
            <Image src="/icons/moon.svg" alt="Moon" width={20} height={20} />
          )}
        </div>
      </div>
    </div>
  )
}

Light and Dark Mode - Only Dark

Add this line to your global CSS file (e.g. globals.css) — it's a one-time setup step, not part of the component below.

@custom-variant dark (&:where(.dark, .dark *));
components/ThemeToggle.js
'use client'

import { useEffect, useState } from 'react'
import { Sun, Moon } from 'lucide-react'

export default function ThemeToggle() {
  const [theme, setTheme] = useState('light')

  useEffect(() => {
    const saved = localStorage.getItem('theme')

    if (saved) {
      setTheme(saved)
      document.documentElement.classList.toggle('dark', saved === 'dark')
    } else {
      const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
      const initial = systemDark ? 'dark' : 'light'

      setTheme(initial)
      document.documentElement.classList.toggle('dark', systemDark)
    }
  }, [])

  const toggleTheme = () => {
    const newTheme = theme === 'dark' ? 'light' : 'dark'

    setTheme(newTheme)
    localStorage.setItem('theme', newTheme)

    document.documentElement.classList.toggle('dark', newTheme === 'dark')
  }

  return (
    <button
      onClick={toggleTheme}
      className="group flex items-center gap-2 px-4 py-3 rounded-full bg-neutral-900/90 border border-neutral-800 dark:shadow-sm text-neutral-200 dark:text-neutral-300 dark:hover:text-apple-blue transition-all duration-300 ease-out hover:scale-[1.03] active:scale-95 cursor-pointer">
      <div className={`transition-transform duration-500 group-hover:rotate-12 `}>
        {theme === 'light' ? (
          <Sun size={20} stroke="#f59e0b" fill="#fde68a" strokeWidth={2} />
        ) : (
          <Moon size={20} stroke="#6498FF" fill="#D5E3FF" strokeWidth={2} />
        )}
      </div>

      <span className="text-sm font-medium">{theme === 'light' ? 'Light Mode' : 'Dark Mode'}</span>
    </button>
  )
}

Dark and Light Button

Add this line to your global CSS file (e.g. globals.css) — it's a one-time setup step, not part of the component below.

@custom-variant dark (&:where(.dark, .dark *));
components/ThemeToggle.js
'use client'

import { useEffect, useState } from 'react'
import { Sun, Moon } from 'lucide-react'

export default function ThemeToggle() {
  const [theme, setTheme] = useState('light')

  // Läs initialt tema
  useEffect(() => {
    const saved = localStorage.getItem('theme')

    if (saved) {
      setTheme(saved)
      document.documentElement.classList.toggle('dark', saved === 'dark')
    } else {
      const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
      const initial = systemDark ? 'dark' : 'light'

      setTheme(initial)
      document.documentElement.classList.toggle('dark', systemDark)
    }
  }, [])

  const toggleTheme = () => {
    const newTheme = theme === 'dark' ? 'light' : 'dark'

    setTheme(newTheme)
    localStorage.setItem('theme', newTheme)

    document.documentElement.classList.toggle('dark', newTheme === 'dark')
  }

  return (
    <button
      onClick={toggleTheme}
      className="group flex items-center gap-2 px-4 py-3 rounded-full bg-white/90 dark:bg-neutral-900/90 border border-neutral-200/80 dark:border-neutral-800 dark:shadow-sm text-neutral-600 dark:text-neutral-300 hover:text-apple-blue dark:hover:text-apple-blue transition-all duration-300 ease-out hover:scale-[1.03] active:scale-95 cursor-pointer">
      <div className={`transition-transform duration-500 group-hover:rotate-12 `}>
        {theme === 'light' ? (
          <Sun size={20} stroke="#f59e0b" fill="#fde68a" strokeWidth={2} />
        ) : (
          <Moon size={20} stroke="#6498FF" fill="#D5E3FF" strokeWidth={2} />
        )}
      </div>

      <span className="text-sm font-medium">{theme === 'light' ? 'Light Mode' : 'Dark Mode'}</span>
    </button>
  )
}