Tema oscuro con Nextjs
vie, 3 feb 2023
Hay muchas formas de hacer la gestión de temas de estilos en React y Nextjs, pero todas ellas pasan por tener un array/objecto con todos los estilos de cada uno de los distintos temas, también
otra de las formas es usar variables de css o scss estas últimas están en cada vez en más deshuso. Yo, en particular voy a usar variables de css y fijar un tema por defecto en mi _document . ¿ Por qué aquí ?
Por que _document se ejecuta en servidor no como _app que lo hace en cliente y si usas un useEffect para setear tu tema por defecto o detectar el que tiene el usuario en su sistema operativo,
en el tiempo que se tarda en hacer esta comprobación y añadirlo, puede darse un parpadeo en los estilos de la pagina. Eso puede resultar extraño.
Yo lo hice así:
1 - Variables de css
--white-color: 255, 255, 255;
--color-available-arrow: 95, 91 98;
--blog-header: 53, 45, 55;
--blog-nav: 204, 202, 219;
--blog-header: 255, 255, 255;
2 - Fijar tema por defecto
const Document = (props: Props) => {
<Html lang={props.__NEXT_DATA__.locale} data-theme="light">
3 - Custom hook para cambiar el tema
import React from 'react';
const useDarkMode = (): { theme: null | 'dark' | 'light'; toggleTheme: () => void; scheme: typeof scheme } => {
const [theme, setTheme] = React.useState<null | 'dark' | 'light'>(null);
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);
if (typeof window !== 'undefined' && theme) {
document.documentElement.setAttribute('data-theme', theme);
const toggleTheme = () => {
setTheme(theme === scheme.dark ? scheme.light : scheme.dark);
return { theme, scheme, toggleTheme };
export default useDarkMode;
4 - Usar el hook
const { formatMessage: f } = useIntl();
<div className={styles.container}>
<section className={styles.confg}>
alt={f({ id: 'settings.langAlt' })}
name={f({ id: theme === dark ? 'settings.dark' : 'settings.light' })}
<section className={styles.confg}></section>
Para hacer la prueba en vivo, puedes cambiar el tema en tu sistema operativo y verás que mi sitio web se actualiza automáticamente o también puedes ir a mi pagina de configuración y cambiar el tema.
Todo el código en mi repositorio de github, si te gusta este proyecto, o si el contenido te ha ayudado en algo puedes recompensarme con una ⭐️, Gracias!