Todo produto SaaS que escala além dos primeiros cinco engenheiros bate na mesma parede: a UI fica inconsistente. Botões ficam diferentes em cada página. Espaçamento é arbitrário. Cores variam entre valores hex que são quase — mas não exatamente — o mesmo tom de azul. Um desenvolvedor usa p-4, outro usa p-5, e ninguém lembra qual é o padding "padrão" do card.
Um design system resolve isso. Não um arquivo Figma que ninguém abre — um design system vivo, code-first, que reforça consistência através da mesma ferramenta que seus desenvolvedores já usam: Tailwind CSS.
Na Meld, nosso próprio produto roda sobre um design system baseado em Tailwind com um gradiente azul-para-índigo como assinatura da marca, componentes MagicUI para micro-interações e uma biblioteca de componentes construída no padrão shadcn/ui. Veja como construímos e como você pode construir o seu.
Por Que Tailwind para Design Systems
Design systems tradicionalmente vivem em dois lugares: uma ferramenta de design (Figma, Sketch) e uma biblioteca de componentes (Storybook + styled-components ou CSS modules). O problema é sincronização. Designers atualizam tokens no Figma; desenvolvedores não percebem por semanas. Uma nova cor é adicionada ao código que não existe no arquivo de design. A divergência é inevitável.
Tailwind elimina essa lacuna. Seus design tokens — cores, espaçamento, tipografia, sombras, border-radius — vivem em um arquivo de configuração. Todo desenvolvedor referencia os mesmos tokens. Não há divergência porque não há uma segunda fonte de verdade.
Tailwind CSS 4 tornou isso ainda mais poderoso com sua configuração CSS-first. Tokens são definidos em CSS usando @theme, tornando-os acessíveis tanto para utilitários Tailwind quanto para CSS puro quando necessário. A configuração é o sistema.
Camada 1: Design Tokens
Design tokens são os blocos de construção atômicos. Acerte esses e tudo downstream fica mais fácil.
Cores
Defina uma escala de cores semântica, não apenas valores brutos:
@theme {
--color-primary-50: #eff6ff;
--color-primary-100: #dbeafe;
--color-primary-200: #bfdbfe;
--color-primary-300: #93c5fd;
--color-primary-400: #60a5fa;
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--color-primary-700: #1d4ed8;
--color-primary-800: #1e40af;
--color-primary-900: #1e3a8a;
--color-primary-950: #172554;
--color-destructive: #ef4444;
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-background: #ffffff;
--color-foreground: #0f172a;
--color-muted: #64748b;
--color-border: #e2e8f0;
}
Regras:
- Use nomes semânticos (
primary,destructive,muted), não nomes de cor (blue,red,gray). Quando fizer rebrand, você muda um arquivo em vez de 400 componentes. - Defina uma escala completa (50-950) para suas cores primárias e neutras. Você vai precisar das variações sutis para estados hover, estados desabilitados e backgrounds.
- Mantenha a paleta enxuta. Três a quatro cores de destaque no máximo. Cada cor adicional é uma decisão que seus desenvolvedores precisam tomar.
Espaçamento
A escala de espaçamento padrão do Tailwind (0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8...) já é bem projetada. Restrinja seu uso a um subconjunto:
Espaçamento interno de componentes: p-2, p-3, p-4, p-6 Espaçamento de seções: py-12, py-16, py-24 Gaps entre elementos: gap-2, gap-3, gap-4, gap-6, gap-8
Documente quais valores de espaçamento são aprovados para quais contextos. Quando desenvolvedores perguntarem "quanto padding um card leva?" a resposta deve ser um valor, não uma decisão subjetiva.
Tipografia
Defina uma escala tipográfica e siga-a:
@theme {
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
}
Mapeie para uso semântico: texto corpo é text-base, texto secundário é text-sm text-muted, headings seguem uma hierarquia rígida. Nunca pule níveis de heading por dimensionamento visual — use CSS em vez disso.
Sombras e Bordas
@theme {
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-full: 9999px;
}
A maioria dos apps SaaS precisa de exatamente três níveis de sombra e três border-radius. Mais que isso cria inconsistência.
Camada 2: Biblioteca de Componentes
Com tokens definidos, construa sua biblioteca de componentes. O padrão shadcn/ui — onde componentes são copiados para seu projeto em vez de importados de um pacote — é a melhor abordagem para design systems de SaaS.
Por Que Copy-Paste em Vez de Pacote
Bibliotecas de componentes tradicionais (Material UI, Chakra UI) são distribuídas como pacotes npm. Você importa e customiza via props ou temas. Isso funciona até não funcionar — quando você precisa de uma variante de botão que não existe, um layout que a biblioteca não suporta, ou um estilo que conflita com as opiniões da biblioteca.
O padrão shadcn/ui te dá ownership total. Componentes vivem no seu código. Você modifica diretamente. Não há luta contra internos da biblioteca ou espera por PRs upstream serem mergeados. Essa filosofia se alinha com por que ownership total do código importa para startups.
Componentes Core que Todo SaaS Precisa
Construa estes primeiro — eles cobrem 80% da sua UI:
Button. Quatro variantes (primary, secondary, outline, ghost), três tamanhos (sm, md, lg), estado de loading, estado desabilitado, suporte a ícone. Esse único componente aparece mais do que qualquer outro.
Input. Text, email, password, number, textarea. Posicionamento consistente de label, estilização de estado de erro, texto auxiliar. Combine com uma biblioteca de formulários (React Hook Form) para validação.
Card. Container com padding, borda, sombra e border-radius consistentes. Slots de header, body e footer. Usado em dashboards, painéis de configurações, tabelas de preços — em todo lugar.
Dialog/Modal. Modal acessível com focus trapping, dismiss por teclado e backdrop. Use primitivos Base UI ou Radix para a camada de acessibilidade; estilize com Tailwind.
Table. Ordenável, paginada, com ações por linha. Apps SaaS vivem em tabelas — gerenciamento de usuários, histórico de cobranças, logs de auditoria, visualizações de dados.
Badge/Tag. Indicadores de status com cores semânticas (success, warning, destructive, neutral). Usado em tabelas, cards e itens de lista.
Dropdown Menu. Menus de navegação, menus de ação, menus de usuário. Novamente, use Radix ou Base UI para acessibilidade; Tailwind para estilização.
Toast/Notification. Feedback para ações assíncronas. Variantes success, error, warning, info.
Design da API de Componentes
Todo componente deve seguir estes princípios:
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost'
size?: 'sm' | 'md' | 'lg'
loading?: boolean
disabled?: boolean
children: React.ReactNode
className?: string // Sempre permita override via className
}
Sempre aceite className para overrides. Desenvolvedores vão precisar ajustar margens, larguras ou posicionamento em contextos específicos. Tailwind Merge (twMerge) garante que classes de override vencem sem batalhas de especificidade.
Use cva (class-variance-authority) para gerenciamento de variantes. Mantém a lógica de variantes limpa e type-safe:
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
{
variants: {
variant: {
primary: 'bg-primary-600 text-white hover:bg-primary-700',
secondary: 'bg-primary-100 text-primary-700 hover:bg-primary-200',
outline: 'border border-border hover:bg-primary-50',
ghost: 'hover:bg-primary-50',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-sm',
lg: 'h-12 px-6 text-base',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
)
Camada 3: Dark Mode
Dark mode não é opcional para produtos SaaS em 2026. Desenvolvedores esperam e muitos usuários preferem para sessões longas de trabalho.
A variante dark: do Tailwind torna a implementação direta, mas o segredo está na arquitetura dos seus tokens:
:root {
--color-background: #ffffff;
--color-foreground: #0f172a;
--color-card: #ffffff;
--color-border: #e2e8f0;
--color-muted: #64748b;
}
.dark {
--color-background: #0f172a;
--color-foreground: #f8fafc;
--color-card: #1e293b;
--color-border: #334155;
--color-muted: #94a3b8;
}
Quando seus componentes referenciam tokens semânticos (bg-background, text-foreground, border-border), dark mode funciona automaticamente. Sem overrides dark: por componente.
Armadilha comum: cores hard-coded. Se um desenvolvedor escreve bg-white em vez de bg-background, dark mode quebra para aquele elemento. Crie regras de lint para valores de cor hard-coded no seu pipeline de CI.
Camada 4: Design Responsivo
Dashboards SaaS são primariamente aplicações desktop, mas páginas de configurações, fluxos de onboarding e páginas de marketing públicas devem funcionar no mobile. Defina o comportamento de breakpoints explicitamente:
Mobile-first para páginas públicas. Marketing, preços, blog, documentação — essas recebem tráfego mobile significativo.
Desktop-first para páginas do app. Dashboards, tabelas de dados, formulários complexos — projete para desktop, depois garanta que mobile não quebre. Usuários podem acessar funcionalidade básica no mobile, mas a experiência completa é desktop.
Responsividade a nível de componente. Cada componente deve documentar seu comportamento responsivo. Um DataTable pode colapsar para layout baseado em cards no mobile. Uma Sidebar se torna um drawer deslizante. Defina esses padrões uma vez e reutilize.
Camada 5: Sistema de Animações
Animações sutis fazem produtos SaaS parecerem polidos. Animações pesadas fazem parecerem lentos. A linha é tênue.
Defina um sistema de animações restrito:
@theme {
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--duration-fast: 150ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
}
Animações aprovadas:
- Fade in/out para modais e tooltips (
duration-fast) - Slide para drawers e painéis (
duration-normal) - Scale para botões ao pressionar (
duration-fast) - Pulse de skeleton para estados de loading
Animações proibidas:
- Qualquer coisa mais longa que 500ms
- Bouncing, shaking ou jiggling (a menos que seja estado de erro)
- Animações que bloqueiam interação do usuário
Usamos componentes MagicUI para micro-interações específicas — animações sutis de gradiente em CTAs, tickers numéricos para métricas e efeitos de revelação de texto em landing pages. Isso adiciona personalidade sem desacelerar a experiência. O segredo é restringir onde aparecem — páginas de marketing sim, dashboards com dados densos não.
Governança: Mantendo o Sistema Vivo
Um design system sem governança vira sugestão. Enforce:
Regras de lint. Use plugins ESLint para sinalizar cores hard-coded, valores de espaçamento não aprovados e atributos de acessibilidade ausentes. Boas práticas de TypeScript se estendem às APIs dos seus componentes — tipagem rígida previne uso incorreto.
Documentação de componentes. Todo componente recebe um guia de uso com exemplos de faça/não faça. Usamos Storybook para documentação interativa, mas até arquivos markdown no diretório do componente funcionam.
Auditorias regulares. Mensalmente, escaneie o código por estilos únicos que deveriam ser componentes. Se três desenvolvedores construíram cards similares com estilos ligeiramente diferentes, consolide em um único componente Card.
Changelog do design system. Quando adicionar, modificar ou depreciar um componente, documente. Desenvolvedores devem saber o que mudou e por quê.
O ROI de Acertar Nisso
Um design system Tailwind bem construído tipicamente entrega:
- 30-50% mais velocidade no desenvolvimento de UI uma vez que a biblioteca de componentes está estabelecida
- Quase zero bugs de UI por inconsistência (cores erradas, espaçamento desalinhado)
- Onboarding mais fácil para novos desenvolvedores — o sistema ensina os padrões
- Consistência de marca em cada tela sem enforcement manual
Isso impacta diretamente a velocidade com que você lança seu MVP e itera sobre ele. O design system é um investimento que compõe a cada feature que você constrói sobre ele.
Comece com tokens. Construa componentes core. Adicione dark mode. Restrinja suas animações. Governe o sistema. Seu eu do futuro — e cada desenvolvedor que entrar no seu time — vai agradecer.
