Primeiramente, por que precisamos implementar tema dark e light nos nossos projetos?

Ter esse recurso não é um requisito que fará seu projeto ter ou não mais acesso, porém ajuda muito na experiência de uso, pois existem pessoas com diferentes preferências. Entendido esse ponto, vamos ao que interessa! 😄

Entendendo o recurso no Tailwind

Para configurarmos esse recurso no Tailwind, precisamos apenas adicionar ou remover a classe dark no elemento do HTML e usar o prefixo dark: nas classes dos elementos que desejamos ter estilos diferentes para cada tema.

Por exemplo:

Nesse cenário, o fundo será bg-gray-800 como padrão (modo claro) e bg-gray-500 quando o tema escuro estiver ativo.

Como funciona no Next.js

No Next.js é um pouco diferente, pois é necessário o apoio de uma biblioteca chamada next-themes.
Importante: você não é obrigado a usá-la — é totalmente possível implementar o mesmo recurso manualmente — porém, ela facilita bastante o desenvolvimento.

Vamos ver exemplos usando e não usando a biblioteca.

Exemplo sem usar a biblioteca

Aqui, você será responsável por:

  • Gerenciar o valor do tema no localStorage;
  • Detectar qual tema o sistema do usuário está utilizando para proporcionar uma melhor experiência.
// hooks/useTheme.ts
import { useEffect, useState } from 'react';

type Theme = 'light' | 'dark';

export function useTheme() {
  const [theme, setTheme] = useState('light');

  // Detecta preferências do sistema
  useEffect(() => {
    const savedTheme = localStorage.getItem('theme') as Theme | null;
    if (savedTheme) {
      setTheme(savedTheme);
    } else {
      const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
      setTheme(prefersDark ? 'dark' : 'light');
    }
  }, []);

  // Atualiza a classe no  e salva no localStorage
  useEffect(() => {
    const root = document.documentElement;
    if (theme === 'dark') {
      root.classList.add('dark');
      root.classList.remove('light');
    } else {
      root.classList.add('light');
      root.classList.remove('dark');
    }
    localStorage.setItem('theme', theme);
  }, [theme]);

  return { theme, setTheme };
}

Exemplo usando a biblioteca next-themes

// provider/theme-provider.ts
'use client'

import { ThemeProvider as NextThemesProvider } from 'next-themes'
import * as React from 'react'

function ThemeProvider({ children, ...props }: React.ComponentProps) {
  const [mounted, setMounted] = React.useState(false)

  React.useEffect(() => {
    setMounted(true)
  }, [])

  if (!mounted) {
    return <>{children}>
  }

  return {children}
}

export { ThemeProvider }

Usando no layout raiz da aplicação:

async function RootLayout({ children }: { children: ReactNode }) {
  return (
    
      
        
          {children}
        
      
    
  )
}

Ao usar a lib next-themes, ela já traz muitos recursos prontos, como:

  • defaultTheme="system", que automaticamente respeita a preferência do sistema do usuário;
  • Controle do tema via classes (class) no HTML;
  • Entre outras configurações que você pode conferir na documentação oficial: 👉 next-themes no npm

Conclusão

Ter tema dark e light no seu sistema não é um ponto crucial, mas é muito importante para melhorar a usabilidade e a interação do usuário com o seu projeto.