DEV Community

Cover image for Implementando tema dark e light no Next.js com Tailwind
Junior
Junior

Posted on • Edited on

2

Implementando tema dark e light no Next.js com Tailwind

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 <body> do HTML e usar o prefixo dark: nas classes dos elementos que desejamos ter estilos diferentes para cada tema.

Por exemplo:

<div class="bg-gray-800 dark:bg-gray-500"></div>
Enter fullscreen mode Exit fullscreen mode

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<Theme>('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 <html> 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 };
}
Enter fullscreen mode Exit fullscreen mode

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<typeof NextThemesProvider>) {
  const [mounted, setMounted] = React.useState(false)

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

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

  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}

export { ThemeProvider }
Enter fullscreen mode Exit fullscreen mode

Usando no layout raiz da aplicação:

async function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="pt-BR">
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}
Enter fullscreen mode Exit fullscreen mode

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.

Embedded BI Dashboards are 💩 Building them yourself is 💩

Embedded BI Dashboards are 💩 Building them yourself is 💩

Use our developer toolkit to build fast-loading, native-feeling dashboards for your customers (without the sh*t).

Get early access

Top comments (1)

Collapse
 
igordsgoncalves profile image
Igor Gonçalves

Teus posts são muito bons! Obrigado!

JavaScript-ready auth and billing that just works

JavaScript-ready auth and billing that just works

Stop building auth from scratch. Kinde handles authentication, user management, and billing so you can focus on what matters - shipping great products your users will love.

Get a free account

👋 Kindness is contagious

Explore this practical breakdown on DEV’s open platform, where developers from every background come together to push boundaries. No matter your experience, your viewpoint enriches the conversation.

Dropping a simple “thank you” or question in the comments goes a long way in supporting authors—your feedback helps ideas evolve.

At DEV, shared discovery drives progress and builds lasting bonds. If this post resonated, a quick nod of appreciation can make all the difference.

Okay