I'm running NextJS with Chakra UI and the problem is when useSystemColorMode
is set to true
, it ignores the user's choice on page refresh and sets it back to the system color mode. For ex. system color mode is dark and the user toggles the button to light mode and then refreshes the page, which automatically undos the light mode and sets it back to dark. I expect it to remain light.
Note: When using system as initial color mode, the theme will change with the system preference. However, if another theme is manually selected by the user then that theme will be used on the next page load. To reset it to system preference, simply remove the chakra-ui-color-mode entry from localStorage.
What I expect is the initial color mode to be the system color mode (in my case = dark) and when the user toggles the button to light mode, on page refresh it should remain light.
import { Button, useColorMode } from '@chakra-ui/react';
import Head from 'next/head';
import Link from 'next/link';
import { LoginWithCentredForm } from '@components/LoginWithCentredForm';
const Dogs = () => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<>
<Head>
<title>Dogs</title>
</Head>
<h1>Dogs</h1>
<Button onClick={toggleColorMode}>
Toggle {colorMode === 'light' ? 'Dark' : 'Light'}
</Button>
<h2>
<Link href="/">
<a>Go back home!</a>
</Link>
<LoginWithCentredForm />
</h2>
</>
);
};
export default Dogs;
import { extendTheme, ThemeConfig } from '@chakra-ui/react';
export const config: ThemeConfig = {
initialColorMode: 'light',
useSystemColorMode: true,
};
export const theme = extendTheme({
config,
fonts: {
heading: 'Work Sans, system-ui, sans-serif',
body: 'Inter, system-ui, sans-serif',
},
});
import { ColorModeScript } from '@chakra-ui/react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { theme } from '../theme';
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@700&family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</Head>
<body>
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
import type { AppProps } from 'next/app';
import { ChakraProvider, CSSReset } from '@chakra-ui/react';
import { theme } from '../theme';
const App = ({ Component, pageProps }: AppProps) => {
return (
<ChakraProvider theme={theme}>
<CSSReset />
<Component {...pageProps} />
</ChakraProvider>
);
};
export default App;
I used useEffect to toggle the color mode to the correct one right after the component mounts with 1.5 seconds delay, I noticed it doesn't work without some delay.
useEffect(() => {
if (localStorage.getItem('chakra-ui-color-mode') === 'light' && colorMode === 'dark') {
setTimeout(() => toggleColorMode(), 1500)
} else if (localStorage.getItem('chakra-ui-color-mode') === 'dark' && colorMode === 'light') {
setTimeout(() => toggleColorMode(), 1500)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])