Cookies
This website uses cookies to improve the user experience, more information on the legal information path.
Notes
0
years
0
mons
0
days
0
hour
0
mins
0
secs
Sat16Mar8:23 PM
This is the background image
2

Dark theme with Nextjs

Fri, Feb 3, 2023

There are many ways to manage style themes in React and Nextjs, but all of them involve having an array/object with all the styles of each of the different themes. another way is to use css or scss variables these last ones are in more and more disuse. I, in particular, am going to use css variables and set a default theme in my _document. Why here ?

Because _document runs on server not like _app which runs on client and if you use a useEffect to set your default theme or detect the one the user has on their operating system, in the time it takes to do this check and add it, there can be a flicker in the page styles. That can be strange.

I did it like this:

1 - css variables

globals.css

:root {
/* commons */
--white-color: 255, 255, 255;
--color-available-arrow: 95, 91 98;
...;
}
[data-theme='dark'] {
--blog-nav: 48, 41, 51;
--blog-header: 53, 45, 55;
...;
}
[data-theme='light'] {
--blog-nav: 204, 202, 219;
--blog-header: 255, 255, 255;
...;
}

2 - Set default theme

_document.tsx

const Document = (props: Props) => {
return (
<Html lang={props.__NEXT_DATA__.locale} data-theme="light">
)
}

3 - Custom hook to change theme

useDarkMode.ts

import React from 'react';
const scheme = {
light: 'light' as const,
dark: 'dark' as const,
};
const useDarkMode = (): { theme: null | 'dark' | 'light'; toggleTheme: () => void; scheme: typeof scheme } => {
const [theme, setTheme] = React.useState<null | 'dark' | 'light'>(null);
React.useEffect(() => {
if (typeof window !== 'undefined' && window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handler = (event: MediaQueryListEvent) => {
setTheme(event.matches ? scheme.dark : scheme.light);
};
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}
}, []);
React.useEffect(() => {
if (typeof window !== 'undefined' && theme) {
document.documentElement.setAttribute('data-theme', theme);
}
}, [theme]);
const toggleTheme = () => {
setTheme(theme === scheme.dark ? scheme.light : scheme.dark);
};
return { theme, scheme, toggleTheme };
};
export default useDarkMode;

4 - Using the hook

settings.tsx

const Content = () => {
const { formatMessage: f } = useIntl();
const {
theme,
scheme: { dark },
toggleTheme,
} = useDarkMode();
return (
<div className={styles.container}>
<section className={styles.confg}>
<IconWithName
icon="/theme.png"
alt={f({ id: 'settings.langAlt' })}
name={f({ id: theme === dark ? 'settings.dark' : 'settings.light' })}
onClick={toggleTheme}
/>
</section>
<section className={styles.confg}></section>
</div>
);
};

To do the live test, you can change the theme on your operating system and you will see that my website updates automatically or you can also go to my settings page and change the theme.

All the code in my github repository, if you like this project, or if the content has helped you in any way you can reward me with a ⭐️, Thanks!