Design system com Tailwind: consistência em 3 configs
Uso Tailwind em tudo. Mas no começo, cada projeto era um caos visual. Cores diferentes, espaçamentos aleatórios, componentes que não batiam um com o outro. Aí criei um design system minimalista que roda em todos meus projetos. Três linhas de config, muito ganho.
O mínimo que um dev solo precisa é consistência. Não precisa de Shadcn, Chakra ou Material. Só de um Tailwind bem organizado, tokens claros e componentes reutilizáveis.
Tokens de cor
Comece pelo tailwind.config.js. Estenda as cores padrão com sua paleta.
export default {
theme: {
extend: {
colors: {
brand: {
50: "#f0f9ff",
100: "#e0f2fe",
500: "#0ea5e9",
600: "#0284c7",
900: "#082f49"
},
surface: {
50: "#fafafa",
100: "#f5f5f5",
500: "#737373",
900: "#171717"
}
}
}
}
}
Nomeie por função, não por cor. Não use blue-500, use brand-500. Não gray-100, use surface-100. Quando você quer mudar a paleta, muda aqui e pronto. Todos os componentes acompanham.
Mantenha a paleta pequena. Cinco tons por cor. Não precisa de 12 variações.
Tipografia
Defina peso, tamanho e line-height uma vez.
extend: {
fontSize: {
xs: ["0.75rem", { lineHeight: "1rem" }],
sm: ["0.875rem", { lineHeight: "1.25rem" }],
base: ["1rem", { lineHeight: "1.5rem" }],
lg: ["1.125rem", { lineHeight: "1.75rem" }],
xl: ["1.25rem", { lineHeight: "1.75rem" }],
"2xl": ["1.5rem", { lineHeight: "2rem" }]
},
fontFamily: {
sans: ["Inter", "sans-serif"]
}
}
Use uma fonte só. Inter, Poppins, Nunito. Uma. Depois você não fica escolhendo fonte no meio do projeto.
Pesos: 400 normal, 500 semi-bold, 600 bold. Três apenas. Seus designs fica menos confuso.
Espaçamento
Tailwind já tem um sistema de spacing bom. Estenda só se precisar.
extend: {
spacing: {
gutter: "2rem",
section: "4rem"
}
}
Use gap-4, p-3, m-2 normalmente. O padrão do Tailwind funciona.
Dica: use variáveis de espaçamento pra seções inteiras. Coloque section-spacing em componentes de larga escala.
Componentes base
Faça isso em um arquivo separado. Tipo components/base.css ou dentro de seus componentes.
Botão básico:
export function Button({ variant = "primary", children, ...props }) {
const baseStyles = "px-4 py-2 rounded-lg font-medium transition-colors"
const variants = {
primary: "bg-brand-500 text-white hover:bg-brand-600",
secondary: "bg-surface-100 text-surface-900 hover:bg-surface-200",
ghost: "bg-transparent text-brand-500 hover:bg-brand-50"
}
return <button className={`${baseStyles} ${variants[variant]}`} {...props}>{children}</button>
}
Card simples:
export function Card({ children }) {
return <div className="bg-white rounded-lg shadow-sm p-6 border border-surface-100">{children}</div>
}
Input com estilo consistente:
export function Input({ label, ...props }) {
return (
<div>
{label && <label className="block text-sm font-medium mb-2 text-surface-900">{label}</label>}
<input
className="w-full px-3 py-2 border border-surface-200 rounded-lg focus:outline-none focus:border-brand-500"
{...props}
/>
</div>
)
}
Pronto. Você tem um botão que parece botão. Um card que parece card. Tudo coeso.
Como reusar em projetos
Coloque esses componentes em uma pasta lib/components. Quando cria projeto novo, copia a pasta inteira.
Ou versione em um repositório privado no GitHub. Importe diretamente.
Cada projeto novo que você pega, 20 minutos de setup da paleta, mais 30 minutos ajustando cores pro cliente. Feito.
Por que não usar UI framework
Shadcn é ótimo. Mas ganha dependências, configuração de build, headless components que você tem que estilizar mesmo assim.
Se você trabalha com clientes pequenos que querem site “simples”, livraria pesada não vale.
Tailwind puro funciona. Fica rápido de carregar, você controla tudo, componentes são seus.
Estrutura prática
Assim que começo projeto novo com Astro:
src/
lib/
colors.ts (exporta tokens)
spacing.ts (exporta espaçamento)
components/
Button.astro
Card.astro
Input.astro
pages/
index.astro
Arquivo lib/colors.ts:
export const colors = {
brand: "brand-500",
brandHover: "brand-600",
surface: "surface-100",
text: "surface-900"
}
Componentes importam daí. Mudança global, uma linha.
Mantendo consistência
Quando você tá refazendo o portfólio de um cliente, reutiliza a mesma paleta em tudo. Mesmo espaçamento. Mesmos tamanhos de texto.
Site dele fica coeso. Layout parece que foi pensado junto. Não é coincidência, é design system.
Pra mim, isso levantou a qualidade dos meus projetos. Clientes percebem quando tudo combina.
Leia também: React vs Astro | Astro 5: o que mudou | Case GPM2
- Criar tokens de cor nomeados por função
- Definir tipografia com uma fonte, três pesos
- Usar espaçamento padrão do Tailwind
- Componentes Button, Card, Input funcionando
- Exportar colors.ts e reusar em projetos
- Versionar componentes em pasta lib
- Validar que paleta funciona em diferentes contextos
Design system não é coisa complexa. É deixar as decisões claras.
Por que design system pra dev solo
Devs solo ganham tempo. Sem design system, cada projeto é reset. Paleta diferente, componentes diferentes, layout não bate. Design system transfere 80% das decisões de estilo pro projeto anterior.
Clientes veem qualidade melhorada. Sites ficam com identidade visual mais forte porque estão usando paleta consistente. Layouts parecem pensados, não acidentais.
Manutenção fica fácil. Cliente muda depois de 6 meses pra “adicionar feature nova”. Você já sabe qual é a paleta, qual é o espaçamento, não precisa descobrir de novo.
Portfólio fica mais profissional. Quando você mostra 5 projetos, todos parecem do mesmo estúdio porque compartilham linguagem visual. Não parece que cada projeto foi feito por pessoa diferente.
Conversei com 12 devs em grupos de comunidade. Os que tinham design system fechado entregavam projetos 25% mais rápido. Sem sacrificar qualidade.
Evitando over-engineering
Tem tentação em deixar o design system complexo demais. “Vou adicionar 5 variações de button.” Não. Se você não usa, é peso.
Meu design system tem 3 tons de cor por variável. 1 font. 3 pesos. 3 tamanhos base. Tudo mais é combinação. Simples, replicável, funciona em produção.
Comecei tentando clonar Tailwind inteiro. Gerava 500 linha de config. Aí enfim peguei e deletei tudo que nunca usava. Resultado? 50 linhas. Quatro projetos rodando. Nada quebrou.
Quando expandir o sistema
Conforme você pega mais clientes com padrões similares, seu design system cresce naturalmente. Não force. Só adicione quando vê que precisa em 2+ projetos.
Exemplo: peguei 3 clientes de clínica. Os 3 queriam timeline pra “nossa história”. Aí criei componente Timeline reutilizável. Agora faz parte do sistema.
Mas um cliente pediu componente de “carrossel de depoimentos”. Nunca mais usei. Não entrou no sistema. Sistema fica leve.
Estrutura final
Coloque tudo versionado em repo privado. Quando começa projeto novo, puxa o template.
design-system-v2/
tailwind.config.js
src/
lib/
colors.ts
spacing.ts
typography.ts
components/
Button.astro
Card.astro
Input.astro
Badge.astro
Modal.astro
patterns/
Header.astro
Footer.astro
Hero.astro
Repo fica com README explicando o sistema. Coloca screenshot de como componentes se parecem. Novo projeto, clona esse repo, customiza cores pro cliente, começar a build.
Design system é infraestrutura de código, não product. Não dedica muito tempo aqui. Dedica tempo em manter prático.
Migração entre projetos
A parte que mais economiza tempo é quando pego um projeto novo de clínica odontológica. Clono o repo do design system, abro o tailwind.config.js, troco 4 cores e pronto. O projeto novo já tem botões, cards, inputs, header e footer funcionando. O que antes levava 2 dias de setup agora leva 40 minutos.
No Family Pilates, o design system me permitiu focar no conteúdo desde o primeiro dia. Não perdi tempo decidindo tamanho de fonte ou espaçamento entre seções. Tudo já estava definido. Resultado: entrega 5 dias antes do prazo.
Quando o cliente pede revisão, a mudança é cirúrgica. “Quero o azul mais escuro.” Troco uma variável CSS. Todos os botões, links e destaques mudam junto. Sem buscar e substituir em 30 arquivos diferentes.
Design system vs biblioteca de componentes
Tem gente que confunde os dois. Biblioteca de componentes é Shadcn, Radix, Material UI. São prontas, opinadas, pesadas. Design system é seu. É o conjunto de decisões visuais que você aplica em todos os projetos.
| Design system próprio | Biblioteca pronta | |
|---|---|---|
| Controle | Total | Limitado ao que a lib oferece |
| Peso | Mínimo (só o que usa) | Pesado (importa o pacote inteiro) |
| Aprendizado | Nenhum (você criou) | Precisa aprender a API da lib |
| Consistência | Garantida entre projetos | Depende da versão da lib |
| Manutenção | Você mantém | Equipe da lib mantém |
Pra dev solo que trabalha com sites e LPs, design system próprio ganha. Pra equipe de 10 devs fazendo SaaS complexo, biblioteca pronta faz mais sentido. Saiba onde você está.
Leia mais sobre decisões de stack em React vs Astro e sobre como entregar mais rápido em entregar projetos rápido com IA.
- Tokens de cor nomeados por função, não por nome da cor
- Tipografia com uma fonte e três pesos
- Espaçamento usando escala padrão do Tailwind
- Componentes base funcionando (Button, Card, Input)
- Config versionado em repo privado
- README com screenshots dos componentes
- Testou a paleta em modo claro e escuro
Design system bom é o que você usa. Se tá parado num repo e nunca clona, não é sistema. É decoração.