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

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çãolib/utils.ts— funções utilitáriascomponents/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ável | Uso |
|---|---|
--background | Cor de fundo da página |
--foreground | Cor do texto da página |
--card | Fundo dos cards |
--card-foreground | Texto dos cards |
--popover | Fundo dos popovers |
--popover-foreground | Texto dos popovers |
--primary | Cor principal, usada em botões e links |
--primary-foreground | Texto sobre a cor principal |
--secondary | Cor secundária |
--secondary-foreground | Texto sobre a cor secundária |
--muted | Fundo discreto |
--muted-foreground | Texto discreto |
--accent | Cor de destaque |
--accent-foreground | Texto sobre a cor de destaque |
--destructive | Ações destrutivas, como botões de exclusão |
--destructive-foreground | Texto sobre a cor destrutiva |
--border | Bordas |
--input | Campos de entrada |
--ring | Anel 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çãoattribute="class"indica que o tema será alternado por meio do nome da classedefaultTheme="system"faz o tema seguir a configuração do sistema por padrãoenableSystemativa 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:
globals.cssfoi importado emlayout.tsx?- A configuração
contentdo Tailwind incluicomponents/**/*? - Os caminhos em
components.jsonestão corretos?
Problema 2: a tela pisca durante a troca de tema
Isso geralmente acontece por uma incompatibilidade de hidratação. Confirme que:
- A tag
<html>contémsuppressHydrationWarning - ThemeProvider envolve toda a aplicação
- O valor de
themenão é lido durante a renderização no servidor, quando ele ficaundefined
Problema 3: as variáveis CSS não funcionam
Algumas causas possíveis:
- O nome da variável está errado: use
--primary-foreground, não--primaryForeground - Não existe um estilo correspondente em
.dark - 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:
- Adicione um namespace aos componentes do shadcn, como
shadcn-button - Ajuste a prioridade das layers do Tailwind
- 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:
- Em projetos novos, prefira inicializar pela CLI para evitar o trabalho da configuração manual
- Use variáveis de cores semânticas, como primary e secondary, em vez de nomes de cores específicos
- Teste o contraste nos modos claro e escuro para garantir a legibilidade
- 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
- Documentação oficial do shadcn/ui — Installation
- Documentação oficial do shadcn/ui — Theming
- Documentação oficial do shadcn/ui — Dark Mode
- Generate Custom shadcn/ui Themes
- Theming in shadcn UI: CSS Variables
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
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
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
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
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?
Por que é melhor instalar o shadcn/ui logo ao iniciar um projeto novo?
Por que as variáveis CSS usam valores HSL sem a função hsl()?
Como alterar a cor principal da marca?
Por que o modo escuro pisca durante a troca de tema?
Devo modificar diretamente o código-fonte dos componentes do shadcn?
10 min de leitura · Publicado em: 26 mar 2026 · Atualizado em: 4 set 2026
Tailwind e shadcn/ui na prática
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
O que é shadcn/ui? Guia comparativo com MUI, Chakra UI e outras bibliotecas de componentes
Uma comparação aprofundada entre shadcn/ui, Material-UI, Chakra UI e Ant Design em sete critérios, como tamanho do bundle, flexibilidade de personalização, experiência de desenvolvimento e acessibilidade, para ajudar você a fazer a melhor escolha
Parte 3 de 14
Próximo
Como montar a estrutura de um painel com shadcn/ui: boas práticas de Sidebar e Layout
Aprenda as melhores práticas para integrar a Sidebar do shadcn/ui ao Layout do Next.js. Veja arquitetura de componentes, design responsivo, controle de acesso e exemplos completos para criar um painel administrativo escalável.
Parte 5 de 14



Comentários
Entre com GitHub para comentar