Voltar ao blog
Tutorial

Design system com Tailwind: consistência em 3 configs

Por Flávio Emanuel · · 8 min de leitura

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óprioBiblioteca pronta
ControleTotalLimitado ao que a lib oferece
PesoMínimo (só o que usa)Pesado (importa o pacote inteiro)
AprendizadoNenhum (você criou)Precisa aprender a API da lib
ConsistênciaGarantida entre projetosDepende da versão da lib
ManutençãoVocê mantémEquipe 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.

Próximo passo

Precisa de um dev que entrega de verdade?

Seja pra um projeto pontual, reforço no time, ou parceria de longo prazo. Vamos conversar.

Falar no WhatsApp

Respondo em até 2h durante horário comercial.