Next.js Discord

Discord Forum

Persist theme and toggle switch with local storage

Unanswered
Pollock posted this in #help-forum
Open in Discord
PollockOP
Yo guys, i have the following code:

"use client"
import React, { useEffect, useState } from 'react'

export default function ThemeSwitch() {

    const [theme, setTheme] = useState("light")

    useEffect(() => {
        const theme = localStorage.getItem('theme');
        if (theme){
            setTheme(theme)
        }
      }, []);

    useEffect(() => {
        document.querySelector("body")?.setAttribute("data-theme", theme);
        localStorage.setItem("theme", theme)
    }, [theme])

    //@ts-ignore
    function switchTheme(e) {
        const target = e.target as HTMLInputElement;
    
        if (target.checked) {
            setTheme("dark")
        } else {
            setTheme("light")
        }
    }
    
    return (
    <div>
        <label className="switch col-span-1">
            <input type="checkbox" onChange={switchTheme} defaultChecked={theme == "dark"}/>
            <span className="slider round"></span>
        </label>
    </div>
  )
}

(probably trash) XDDD

but anyway, the theme persistance works, when i toggle on the switch, dark mode gets activated, and stays when i reload the page, however the toggle switch is always untoggled on reload, can anyone tell why?

12 Replies

PollockOP
nvm i got it
@Pollock nvm i got it
what did you change?
PollockOP
"use client"
import React, { useEffect, useState } from 'react'

export default function ThemeSwitch() {

    const [theme, setTheme] = useState("light")

    useEffect(() => {
        const theme = localStorage.getItem('theme');
        if (theme){
            setTheme(theme)
            //@ts-ignore
            document.querySelector('#toggle').checked = (localStorage.getItem('theme') === 'dark')
        }
      }, []);

    useEffect(() => {
        document.querySelector("body")?.setAttribute("data-theme", theme);
        localStorage.setItem("theme", theme)
    }, [theme])

    //@ts-ignore
    function switchTheme(e) {
        const target = e.target as HTMLInputElement;
    
        if (target.checked) {
            setTheme("dark")
        } else {
            setTheme("light")
        }
    }
    
    return (
    <div>
        <label className="switch col-span-1">
            <input id="toggle" type="checkbox" onChange={switchTheme}/>
            <span className="slider round"></span>
        </label>
    </div>
  )
}
looks like this now
removed the defaultchecked prop from the button
added an id to it
and in the first useeffect i added
document.querySelector('#toggle').checked = (localStorage.getItem('theme') === 'dark')
was some kinda runtime issue i guess
I got interested, because I have a problem with localStorage when trying to deploy to Vercel... Been stuck at it for a couple of hours already, can't find a solution.
I'm glad you managed to fix your issue tho
Northern Saw-whet Owl
I recommend using next-themes

https://www.npmjs.com/package/next-themes
Kawakawa
I'd also recommend using ref over querySelector based on id