Capítulo 80 de 108
Sem SSR, um app Vite implementa dark mode com um ThemeProvider customizado próprio (Context API) que lê/grava localStorage e aplica a classe dark/light diretamente no <html>.
React.createContext customizado, sem dependência externa.localStorage (default "vite-ui-theme"), permite múltiplos apps na mesma origem sem conflito.window.matchMedia("(prefers-color-scheme: dark)") em tempo de efeito, não reativo a mudanças do SO após o mount.const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
)
useEffect(() => {
const root = window.document.documentElement
root.classList.remove("light", "dark")
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
root.classList.add(systemTheme)
return
}
root.classList.add(theme)
}, [theme])
documentElement, sem lib externa.<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
{children}
</ThemeProvider>
system no mount/mudança de estado, não escuta o evento change do matchMedia.suppressHydrationWarning nem de lib como next-themes.setTheme sempre persiste em localStorage antes de atualizar o state.