Alternar tema

Guia completo para instalar e personalizar temas do shadcn/ui (com variáveis CSS)

Easton editorial illustration: design-system assembly tray

Na primeira vez que usei o shadcn/ui, fiquei confuso com a ideia de que ele “não é um pacote npm”. Copiar código para dentro do projeto? Isso parecia primitivo demais.

Depois de usá-lo algumas vezes, percebi que esse é justamente o seu grande diferencial: você tem o código-fonte de todos os componentes, pode alterá-los como quiser e não fica preso às limitações visuais de uma biblioteca nem precisa se preocupar com conflitos de versão.

Neste artigo, vamos falar sobre a instalação, a configuração e a personalização de temas do shadcn/ui, com foco no uso de variáveis CSS para criar um design alinhado à sua marca. Ao terminar, você deverá conseguir concluir a configuração básica em 5 minutos e, com mais uma hora de trabalho, ajustar o tema do jeito que quiser.


1. Instalação rápida: duas opções

Opção 1: inicialização pela CLI (recomendada)

Em um projeto novo, basta executar:

npx shadcn@latest init

O comando fará várias perguntas: você quer usar TypeScript ou JavaScript? Qual estilo prefere? Qual será o tema padrão? Todo o processo é interativo; basta seguir as instruções e escolher as opções adequadas.

Ao final da instalação, alguns arquivos e diretórios serão adicionados ao projeto:

  • components.json — arquivo de configuração
  • lib/utils.ts — funções utilitárias
  • components/ui/ — diretório dos componentes

Adicionar um componente também é simples. Para incluir um botão, por exemplo:

npx shadcn@latest add button

O código do componente será copiado automaticamente para components/ui/button.tsx. Depois, basta importá-lo e usá-lo.

Há uma armadilha aqui: se o projeto já estiver em desenvolvimento há algum tempo, provavelmente haverá configurações importantes em tailwind.config.js e globals.css. O comando init do shadcn pode sobrescrever esses arquivos, então o ideal é fazer a instalação logo no início do projeto.

Um blogueiro resumiu bem: trate o shadcn/ui como parte do “primeiro conjunto de dependências” do projeto, em vez de adicioná-lo mais tarde. É uma lição aprendida da maneira difícil.

Opção 2: instalação manual (para projetos existentes)

Se o projeto já está estruturado e o risco de a CLI sobrescrever configurações é grande, faça a instalação manualmente.

O processo tem algumas etapas:

Etapa 1: confirme que o Tailwind CSS está instalado

Os componentes do shadcn são escritos com Tailwind. Se ele ainda não estiver instalado, instale-o primeiro. A documentação oficial explica bem esse processo.

Etapa 2: instale as dependências

npm install class-variance-authority clsx tailwind-merge
npm install lucide-react

O class-variance-authority, abreviado como CVA, será muito útil quando você criar variantes de componentes mais adiante.

Etapa 3: configure o alias de caminho

Adicione isto ao tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]
    }
  }
}

Assim, você poderá importar um componente com @/components/ui/button, sem escrever uma sequência de ../../../.

Etapa 4: crie o arquivo components.json

Crie este arquivo na raiz do projeto:

{
  "style": "new-york",
  "rsc": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}

A linha cssVariables: true é essencial: ela indica que usaremos variáveis CSS no tema, em vez de utility classes do Tailwind.

Etapa 5: adicione os estilos

Inclua os estilos básicos do shadcn em globals.css. Veremos isso em mais detalhes na seção sobre temas.


2. Entendendo o sistema de temas: como funcionam as variáveis CSS

O sistema de temas do shadcn/ui se baseia em uma convenção simples: cada cor tem duas variáveis, background e foreground.

O que isso significa? Veja um exemplo:

:root {
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
}

--primary é a cor de fundo do botão, enquanto --primary-foreground é a cor do texto exibido sobre ele. A vantagem dessa combinação é que, ao alterar uma variável, todos os componentes relacionados são atualizados junto com ela.

Lista de variáveis CSS

Por padrão, o shadcn/ui define estas variáveis:

VariávelUso
--backgroundCor de fundo da página
--foregroundCor do texto da página
--cardFundo dos cards
--card-foregroundTexto dos cards
--popoverFundo dos popovers
--popover-foregroundTexto dos popovers
--primaryCor principal, usada em botões e links
--primary-foregroundTexto sobre a cor principal
--secondaryCor secundária
--secondary-foregroundTexto sobre a cor secundária
--mutedFundo discreto
--muted-foregroundTexto discreto
--accentCor de destaque
--accent-foregroundTexto sobre a cor de destaque
--destructiveAções destrutivas, como botões de exclusão
--destructive-foregroundTexto sobre a cor destrutiva
--borderBordas
--inputCampos de entrada
--ringAnel de foco

Parece muita coisa, mas, quando você entende a lógica de background/foreground, fica fácil memorizar.

O segredo do formato HSL

Talvez você tenha notado que os valores de cor do shadcn não usam o formato HSL padrão:

/* ❌ HSL padrão */
--primary: hsl(222.2, 47.4%, 11.2%);

/* ✅ Formato do shadcn */
--primary: 222.2 47.4% 11.2%;

Por que usar esse formato “sem a função”?

Porque o Tailwind oferece modificadores de opacidade. Por exemplo, bg-primary/50 representa a cor principal com 50% de opacidade. Se a variável contiver a função hsl() completa, esse recurso não funcionará.

Com o valor isolado, o Tailwind adiciona automaticamente hsl() e a opacidade. É uma solução inteligente.


3. Personalizando o tema da sua marca

Método 1: alterar diretamente as variáveis CSS

A maneira mais simples é abrir globals.css, localizar a seção :root e alterar os valores das cores.

Por exemplo, para trocar a cor principal padrão de azul para roxo:

:root {
  --primary: 270 60% 60%;
  --primary-foreground: 0 0% 100%;
}

.dark {
  --primary: 270 60% 70%;
  --primary-foreground: 0 0% 0%;
}

Depois de salvar, todos os botões e links que usam bg-primary ficarão roxos.

Método 2: usar o espaço de cores OKLCH (Tailwind v4)

Se você usa o Tailwind v4, vale considerar o espaço de cores OKLCH. Em comparação com HSL, ele representa a percepção humana das cores com mais fidelidade e produz escalas de cores mais uniformes.

:root {
  --primary: oklch(0.6 0.2 270);
  --primary-foreground: oklch(0.98 0 0);
}

Os três parâmetros de oklch(0.6 0.2 270) são:

  • 0.6 — luminosidade (0–1)
  • 0.2 — croma (aproximadamente 0–0,4)
  • 270 — ângulo de matiz (0–360)

Método 3: gerar o tema com uma ferramenta online

Configurar todas as cores manualmente parece trabalhoso? Você pode usar uma ferramenta online.

Uma opção é o Shadcn Theme Generator.

Escolha uma cor principal e a ferramenta gerará automaticamente um conjunto completo de variáveis CSS, incluindo versões para os temas claro e escuro. Depois, é só copiar e colar em globals.css.


4. Configuração do modo escuro

Alternando o tema com next-themes

O shadcn/ui não inclui um recurso próprio para alternar temas, mas você pode fazer isso com a biblioteca next-themes.

Primeiro, instale-a:

npm install next-themes

Depois, configure-a em layout.tsx:

import { ThemeProvider } from "next-themes"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="pt-BR" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

Alguns pontos importantes:

  • suppressHydrationWarning é obrigatório para evitar avisos de hidratação
  • attribute="class" indica que o tema será alternado por meio do nome da classe
  • defaultTheme="system" faz o tema seguir a configuração do sistema por padrão
  • enableSystem ativa a detecção do tema do sistema

Criando um botão para alternar o tema

Use o hook useTheme para obter o tema atual e a função de troca:

import { useTheme } from "next-themes"
import { Moon, Sun } from "lucide-react"

export function ThemeToggle() {
  const { theme, setTheme } = useTheme()

  return (
    <button
      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
      className="p-2 rounded-md hover:bg-accent"
    >
      {theme === "dark" ? <Sun size={20} /> : <Moon size={20} />}
    </button>
  )
}

Usando o modo escuro por padrão

Se você quer que o site abra no modo escuro por padrão, há duas opções:

Opção 1: definir a classe dark diretamente

<html lang="pt-BR" className="dark">

Nesse caso, o tema ficará fixo no modo escuro e não poderá ser alternado.

Opção 2: definir o tema padrão

<ThemeProvider
  attribute="class"
  defaultTheme="dark"  // Modo escuro por padrão
  enableSystem={false} // Desativa a detecção do sistema
>

Assim, o usuário ainda poderá alternar o tema manualmente, mas o estado inicial será o modo escuro.


5. Personalização avançada: variantes de componentes

Criando variantes personalizadas com CVA

Às vezes, você precisa adicionar diferentes estilos a um botão, como “perigo”, “sucesso” ou “gradiente”. Com CVA, é fácil definir essas variantes.

import { cva, type VariantProps } from "class-variance-authority"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

Depois, use-a no componente:

<button className={buttonVariants({ variant: "destructive", size: "lg" })}>
  Excluir
</button>

Não modifique diretamente o código-fonte dos componentes do shadcn

Essa é uma questão de boas práticas.

O código dos componentes do shadcn fica dentro do seu projeto, então você pode alterá-lo como quiser. Mesmo assim, não é recomendável modificar diretamente os arquivos originais. Em vez disso, crie componentes wrapper.

Por quê? O shadcn atualiza os componentes com frequência. Se você alterar os arquivos originais, terá que fazer o merge manualmente ao atualizar, o que dá bastante trabalho.

Uma abordagem melhor:

// components/brand-button.tsx
import { Button } from "@/components/ui/button"
import { cva } from "class-variance-authority"

const brandButtonVariants = cva("...", {
  variants: {
    brand: {
      primary: "bg-brand-primary text-white",
      secondary: "bg-brand-secondary text-black",
    },
  },
})

export function BrandButton({ brand, ...props }) {
  return <Button className={brandButtonVariants({ brand })} {...props} />
}

Dessa forma, o componente Button original permanece intacto, enquanto você cria seu próprio BrandButton. Futuras atualizações do shadcn não afetarão sua personalização.


6. Problemas comuns e armadilhas

Problema 1: os estilos não funcionam após a instalação

Confira estes pontos:

  1. globals.css foi importado em layout.tsx?
  2. A configuração content do Tailwind inclui components/**/*?
  3. Os caminhos em components.json estão corretos?

Problema 2: a tela pisca durante a troca de tema

Isso geralmente acontece por uma incompatibilidade de hidratação. Confirme que:

  1. A tag <html> contém suppressHydrationWarning
  2. ThemeProvider envolve toda a aplicação
  3. O valor de theme não é lido durante a renderização no servidor, quando ele fica undefined

Problema 3: as variáveis CSS não funcionam

Algumas causas possíveis:

  1. O nome da variável está errado: use --primary-foreground, não --primaryForeground
  2. Não existe um estilo correspondente em .dark
  3. O formato do valor está incorreto: use HSL sem a função ou OKLCH

Problema 4: conflito entre estilos de componentes

Se o projeto já tem um sistema de estilos, ele pode entrar em conflito com o shadcn. Algumas soluções:

  1. Adicione um namespace aos componentes do shadcn, como shadcn-button
  2. Ajuste a prioridade das layers do Tailwind
  3. Use CVA para criar suas próprias variantes sem depender dos estilos padrão

7. Conclusão

Instalar e configurar o shadcn/ui é relativamente simples. O principal é entender a ideia de “copiar código em vez de instalar um pacote”. A vantagem é ter controle total; a desvantagem é que cada projeto precisa manter sua própria versão do código dos componentes.

Na personalização de temas, o sistema de variáveis CSS é muito bem pensado. Basta mudar alguns valores para atualizar as cores de toda a aplicação. Com next-themes, alternar entre os modos claro e escuro também exige apenas algumas linhas de código.

Para terminar, ficam algumas recomendações:

  1. Em projetos novos, prefira inicializar pela CLI para evitar o trabalho da configuração manual
  2. Use variáveis de cores semânticas, como primary e secondary, em vez de nomes de cores específicos
  3. Teste o contraste nos modos claro e escuro para garantir a legibilidade
  4. Crie componentes wrapper em vez de alterar o código-fonte original para facilitar atualizações futuras

Na próxima vez que precisar montar rapidamente uma interface com temas, experimente o shadcn/ui. Depois que você entende a proposta, copiar e colar fica bem mais interessante.



Referências

Instalação e personalização de temas do shadcn/ui

Instale o shadcn/ui do zero, configure o sistema de temas e crie um design alinhado à sua marca

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Inicializar rapidamente pela CLI

    Execute o comando de instalação em um projeto novo:

    • npx shadcn@latest init
    • Escolha TypeScript, o estilo New York e o tema padrão
    • Aguarde a CLI concluir a configuração
  2. 2

    Step 2: Alterar a cor principal da marca

    Edite as variáveis CSS em globals.css:

    • Abra app/globals.css
    • Encontre a variável --primary dentro de :root
    • Substitua pelo valor da cor da sua marca, em HSL ou OKLCH
    • Ajuste também --primary-foreground para garantir o contraste
  3. 3

    Step 3: Configurar o modo escuro

    Instale e configure next-themes:

    • npm install next-themes
    • Adicione ThemeProvider em layout.tsx
    • Defina suppressHydrationWarning para evitar avisos de hidratação
    • Crie um componente para alternar o tema
  4. 4

    Step 4: Criar variantes de componentes

    Use CVA para definir estilos personalizados:

    • Instale class-variance-authority
    • Defina variants e defaultVariants
    • Aplique buttonVariants() no componente
    • Mantenha o componente original do shadcn intacto

FAQ

Qual é a diferença entre o shadcn/ui e uma biblioteca tradicional de componentes de UI?
O shadcn/ui não é um pacote npm: ele copia o código-fonte dos componentes para o seu projeto. A vantagem é ter controle total e liberdade de personalização, sem se preocupar com conflitos de versão; a desvantagem é que cada projeto precisa manter o próprio código dos componentes.
Por que é melhor instalar o shadcn/ui logo ao iniciar um projeto novo?
O comando init do shadcn pode sobrescrever tailwind.config.js e globals.css. Se o projeto já estiver em desenvolvimento há algum tempo, as configurações existentes nesses arquivos poderão ser substituídas. Por isso, quanto antes você instalar, melhor.
Por que as variáveis CSS usam valores HSL sem a função hsl()?
Esse formato, como 222.2 47.4% 11.2%, permite usar modificadores de opacidade do Tailwind. Por exemplo, bg-primary/50 representa a cor principal com 50% de opacidade. Esse recurso não funciona quando o valor contém a função hsl() completa.
Como alterar a cor principal da marca?
Abra globals.css, localize as variáveis --primary e --primary-foreground dentro de :root e substitua os valores pelas cores da sua marca. Depois disso, todos os componentes que usam bg-primary serão atualizados automaticamente.
Por que o modo escuro pisca durante a troca de tema?
Geralmente isso acontece por uma incompatibilidade de hidratação. Confirme que a tag html contém suppressHydrationWarning, que ThemeProvider envolve toda a aplicação e que o tema não é lido durante a renderização no servidor.
Devo modificar diretamente o código-fonte dos componentes do shadcn?
Não é recomendado. Como os componentes do shadcn são atualizados com frequência, qualquer alteração no arquivo original precisará ser mesclada manualmente durante uma atualização. É melhor criar um componente wrapper e manter o original intacto.

10 min de leitura · Publicado em: 26 mar 2026 · Atualizado em: 4 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog