Hey melvin,
The solution looks good and the responsiveness is also pretty good.
a few things to note,
In the ThemeSwitcher Component
<input
type="checkbox"
className="m-t absolute top-0 left-0 z-10 h-full w-full cursor-pointer appearance-none"
checked={darkMode}
role="switch"
aria-checked={darkMode}
onChange={() => setDarkMode(!darkMode)}
/>
when calling the setDarkMode you should prefer to do it using a function since the state update depends on previous state.
<input
type="checkbox"
className="m-t absolute top-0 left-0 z-10 h-full w-full cursor-pointer appearance-none"
checked={darkMode}
role="switch"
aria-checked={darkMode}
onChange={() => setDarkMode((prev) => !prev)}
/>
this should be preferred because sate updates happen asynchronously, check out this resources for more details
using a function in setState medium article
stack overflow question about function in setState
The effect you are running for theme switching, this might affect perfomance as the app gets bigger
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
}
}, [darkMode]);
another way to do this would be to store the theme preference in an app wide state like Context API or redux store and use it in the components.
Overall good solution, well done π