Skip to content

Instantly share code, notes, and snippets.

@timc1

timc1/useTheme.tsx

Created Apr 16, 2020
Embed
What would you like to do?
🌑☀️mode theming hook
import * as React from "react";
type Theme = "system" | "light" | "dark";
const STORAGE_KEY = "theme";
const VALID_THEMES: Theme[] = ["system", "light", "dark"];
const DARK_MODE_MEDIA_QUERY = "(prefers-color-scheme: dark)";
function getAppTheme(): Theme {
if (typeof window !== "undefined") {
const storage = window.localStorage.getItem(STORAGE_KEY) as Theme;
const config: Theme = VALID_THEMES.includes(storage) ? storage : "system";
if (config === "system") {
return window.matchMedia(DARK_MODE_MEDIA_QUERY).matches
? "dark"
: "light";
} else {
return config;
}
} else {
return "system";
}
}
function setAppTheme(theme: Theme) {
if (VALID_THEMES.includes(theme)) {
window.localStorage.setItem(STORAGE_KEY, theme);
if (theme !== "system") {
window.document.documentElement.setAttribute("data-theme", theme);
} else {
window.document.documentElement.removeAttribute("data-theme");
}
}
}
const ThemeContext = React.createContext(undefined);
export function AppThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = React.useState(getAppTheme);
const handleThemeChange = (event: MediaQueryListEvent) => {
const theme = event.matches ? "dark" : "light";
setTheme(theme);
};
React.useEffect(() => {
setAppTheme(theme);
}, [theme]);
React.useEffect(() => {
const mediaQuery = window.matchMedia(DARK_MODE_MEDIA_QUERY);
mediaQuery.addListener(handleThemeChange);
return () => {
mediaQuery.removeListener(handleThemeChange);
};
}, []);
return (
<ThemeContext.Provider value={{ theme }}>{children}</ThemeContext.Provider>
);
}
export default function useAppTheme() {
const { theme } = React.useContext(ThemeContext);
return theme;
}
@timc1

This comment has been minimized.

Copy link
Owner Author

@timc1 timc1 commented Apr 16, 2020

const theme = useTheme() 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.