Tips & Tricks (Atualizado: 02/06/2026)

Dicas de Tailwind CSS com Claude Code: guia prático para UI estável

Tailwind CSS com Claude Code: tokens, responsividade, dark mode, componentes, safelist e checagens visuais em React.

Dicas de Tailwind CSS com Claude Code: guia prático para UI estável

Tailwind CSS permite montar interfaces com pequenas utility classes como p-4, grid, text-sm e rounded-lg. Claude Code acelera esse trabalho porque consegue ler o repositório, editar arquivos, executar comandos e revisar mudanças. O risco é que uma melhoria rápida também gere className enormes, cores inconsistentes, bugs só no mobile, dark mode incompleto ou classes dinâmicas que não entram no CSS de produção.

Este guia mostra um fluxo prático para usar Claude Code com Tailwind CSS de forma segura. Vamos cobrir design tokens, utilities responsivas, extração de componentes, como evitar class soup, dark mode, forms, buttons, cards, safelist, content scanning e checagens visuais com Playwright. Os exemplos usam React + TypeScript, mas o processo vale para Astro, Next.js, Remix, Vite e outros stacks.

As referências oficiais usadas são Tailwind Theme variables, Responsive design, Dark mode, Detecting classes in source files e Adding custom styles. Para React tipado, veja o guia de TypeScript do React. Para Claude Code, use a documentação oficial. Para comparação visual, consulte Playwright Visual comparisons.

Se seus prompts ainda são genéricos, comece por 5 dicas para prompts melhores. Se o objetivo inclui experiência mobile completa, conecte este fluxo com o guia de PWA.

Comece por uma auditoria

Não peça para Claude Code editar arquivos imediatamente. Em Tailwind, os problemas costumam vir de pequenas decisões espalhadas: cores, espaçamentos, breakpoints, estados de formulário, dark mode, CTAs, anúncios e blocos de código. Primeiro peça um relatório.

Revise o uso de Tailwind CSS neste repositório. Não edite arquivos ainda.
Entregue um relatório sobre:

- Design tokens existentes para color, spacing, radius, shadow e typography
- Componentes React com className muito longos
- Layouts que podem quebrar em 375px, 768px ou 1440px
- Cobertura de light/dark mode
- Estilos repetidos em forms, buttons, cards e badges
- Classes Tailwind dinâmicas que podem faltar no CSS de produção
- Checagens visuais existentes: Playwright, Storybook ou navegador manual

No ClaudeCodeLab, Masa já ajustou espaçamento olhando só para desktop. No mobile, o CTA no fim do artigo e o bloco de anúncio ficaram apertados. Uma classe Tailwind parece local, mas pode afetar leitura, cliques e conversão.

Centralize design tokens

Design tokens são valores de design nomeados: cor, espaçamento, fonte, raio, sombra e breakpoint. Tailwind CSS v4 usa @theme, que cria utilities como bg-brand-600 e rounded-card. Em projetos antigos com tailwind.config.ts, o mesmo conceito fica em theme.extend.

/* src/styles/app.css */
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

@theme {
  --font-sans: Inter, system-ui, sans-serif;
  --color-brand-50: #eef6ff;
  --color-brand-100: #d9ebff;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
  --color-ink: #111827;
  --color-muted: #6b7280;
  --color-surface: #ffffff;
  --color-danger: #dc2626;
  --radius-card: 0.75rem;
  --shadow-card: 0 16px 40px rgb(15 23 42 / 0.08);
}

Um bom pedido para Claude Code é: “Use os tokens existentes brand, surface e danger; adicione @theme apenas quando o valor novo for reutilizável.” Isso evita o clássico mix de blue, sky e indigo no mesmo produto.

Responsividade sempre mobile-first

Tailwind é mobile-first. A classe base vale para telas pequenas; sm:, md: e lg: adicionam diferenças para telas maiores. Começar pelo desktop e remendar mobile depois costuma deixar grid, imagem e CTA instáveis.

Melhore o product grid com Tailwind CSS.
Condições:
- 1 coluna em 375px, 2 colunas a partir de 640px, 3 colunas a partir de 1024px
- Imagens sempre quadradas
- Cards com altura consistente
- Botão CTA alinhado no fim do card
- Não altere o tipo Product props
- Depois, confira screenshots mobile e desktop
type Product = {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
};

export function ProductGrid({ products }: { products: Product[] }) {
  return (
    <section className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
      {products.map((product) => (
        <article
          key={product.id}
          className="flex h-full flex-col overflow-hidden rounded-card border border-slate-200 bg-surface shadow-card dark:border-slate-800 dark:bg-slate-950"
        >
          <img
            src={product.imageUrl}
            alt={product.name}
            className="aspect-square w-full object-cover"
          />
          <div className="flex flex-1 flex-col p-4">
            <h3 className="line-clamp-2 text-base font-semibold text-ink dark:text-white">
              {product.name}
            </h3>
            <p className="mt-2 text-sm text-muted dark:text-slate-400">
              {product.price.toLocaleString("pt-BR", {
                style: "currency",
                currency: "BRL",
              })}
            </p>
            <button className="mt-auto rounded-lg bg-brand-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-brand-700 focus:outline-none focus:ring-2 focus:ring-brand-600 focus:ring-offset-2 dark:focus:ring-offset-slate-950">
              Ver detalhes
            </button>
          </div>
        </article>
      ))}
    </section>
  );
}

aspect-square mantém a imagem estável, flex h-full flex-col estabiliza o card e mt-auto coloca o CTA no rodapé.

Extraia componentes antes do class soup

Class soup é um className tão longo que ninguém distingue base, variante e correção pontual. Não esconda tudo com @apply; extraia principalmente botões, cards, badges e inputs repetidos.

import type { ButtonHTMLAttributes, ReactNode } from "react";

type ButtonVariant = "primary" | "secondary" | "danger";

const buttonVariants: Record<ButtonVariant, string> = {
  primary: "bg-brand-600 text-white hover:bg-brand-700 focus:ring-brand-600",
  secondary:
    "border border-slate-300 bg-white text-slate-900 hover:bg-slate-50 focus:ring-slate-400 dark:border-slate-700 dark:bg-slate-900 dark:text-white",
  danger: "bg-danger text-white hover:bg-red-700 focus:ring-danger",
};

function cn(...classes: Array<string | false | null | undefined>) {
  return classes.filter(Boolean).join(" ");
}

type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
  variant?: ButtonVariant;
  loading?: boolean;
  children: ReactNode;
};

export function Button({
  variant = "primary",
  loading = false,
  disabled,
  className,
  children,
  ...props
}: ButtonProps) {
  return (
    <button
      className={cn(
        "inline-flex min-h-10 items-center justify-center rounded-lg px-4 py-2 text-sm font-semibold transition focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60 dark:focus:ring-offset-slate-950",
        buttonVariants[variant],
        className,
      )}
      disabled={disabled || loading}
      {...props}
    >
      {loading ? "Processando..." : children}
    </button>
  );
}

Peça para Claude Code manter classes como strings completas. Evite bg-${color}-600, porque o scanner do Tailwind pode não detectar a classe.

Dark mode, formulários e CTA juntos

Dark mode não é só fundo escuro. Texto, borda, sombra, input, erro, disabled e focus ring precisam ser conferidos. Formulários e CTAs fazem parte da receita, então o estado de erro importa tanto quanto o sucesso.

"use client";

import type { FormEvent } from "react";

type LeadFormProps = {
  onSubmit: (values: { email: string; message: string }) => void;
  error?: string;
};

export function LeadForm({ onSubmit, error }: LeadFormProps) {
  function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    onSubmit({
      email: String(formData.get("email") ?? ""),
      message: String(formData.get("message") ?? ""),
    });
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="space-y-4 rounded-card border border-slate-200 bg-white p-5 shadow-card dark:border-slate-800 dark:bg-slate-950"
    >
      <label className="block text-sm font-medium text-slate-900 dark:text-white">
        Email
        <input
          name="email"
          type="email"
          required
          aria-describedby={error ? "lead-form-error" : undefined}
          className="mt-1 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-brand-600 focus:ring-2 focus:ring-brand-600/20 dark:border-slate-700 dark:bg-slate-900 dark:text-white"
          placeholder="you@example.com"
        />
      </label>

      {error ? (
        <p id="lead-form-error" className="text-sm font-medium text-danger">
          {error}
        </p>
      ) : null}

      <button className="w-full rounded-lg bg-brand-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-brand-700 focus:outline-none focus:ring-2 focus:ring-brand-600 focus:ring-offset-2 dark:focus:ring-offset-slate-950">
        Solicitar consultoria
      </button>
    </form>
  );
}

Para revisar acessibilidade, conecte também com o guia de acessibilidade com Claude Code.

Safelist e content scanning

Tailwind gera CSS a partir das classes detectadas nos arquivos fonte. Se a classe for montada dinamicamente, ela pode faltar em produção. Prefira maps estáticos.

type Status = "success" | "warning" | "danger";

const statusClasses: Record<Status, string> = {
  success: "bg-emerald-50 text-emerald-700 ring-emerald-600/20",
  warning: "bg-amber-50 text-amber-800 ring-amber-600/20",
  danger: "bg-red-50 text-red-700 ring-red-600/20",
};

export function StatusBadge({ status, label }: { status: Status; label: string }) {
  return (
    <span
      className={`inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold ring-1 ring-inset ${statusClasses[status]}`}
    >
      {label}
    </span>
  );
}

Se classes vierem de um pacote externo ou CMS, use @source ou @source inline() com moderação.

@import "tailwindcss";

@source "../node_modules/@acme/ui-kit";
@source inline("bg-emerald-50");
@source inline("text-emerald-700");
@source inline("bg-amber-50");
@source inline("text-amber-800");

Verifique visualmente

Build aprovado não prova que a UI está certa. Com Playwright, capture larguras importantes.

import { expect, test } from "@playwright/test";

const viewports = [
  { name: "mobile", size: { width: 375, height: 812 } },
  { name: "tablet", size: { width: 768, height: 1024 } },
  { name: "desktop", size: { width: 1440, height: 960 } },
];

for (const viewport of viewports) {
  test(`pricing page visual check - ${viewport.name}`, async ({ page }) => {
    await page.setViewportSize(viewport.size);
    await page.goto("/pricing");
    await expect(page.getByRole("main")).toHaveScreenshot(
      `pricing-${viewport.name}.png`,
      { maxDiffPixelRatio: 0.01 },
    );
  });
}

No final, peça para Claude Code listar arquivos alterados, riscos, viewports verificados, dark mode e passos manuais caso Playwright não exista.

Casos de uso e erros comuns

Caso de usoPedido para Claude CodeFoco Tailwind
Landing pageRevisar hero, CTA, preços e depoimentos juntosEspaço, hierarquia, CTA
Dashboard SaaSOrganizar tabelas, filtros, sidebar e empty statesDensidade, overflow, sticky header
Lead formCobrir input, erro, sucesso, loading, disabledFocus ring, labels, alvo mobile
Site de conteúdoRevisar texto, código, anúncios e CTALargura de leitura, scroll do código, links

Os erros comuns são classes dinâmicas, revisão só no desktop, dark mode pela metade, excesso de @apply, muitas cores parecidas, erro de formulário esquecido e falta de screenshots.

CTA e resultado testado

Melhorias de Tailwind devem apoiar o caminho de receita: CTA no fim do artigo, pricing card, formulário de consultoria ou download. ClaudeCodeLab oferece uma cheatsheet gratuita de Claude Code, produtos e templates e treinamento ou consultoria para equipes.

Ao testar este fluxo em páginas do ClaudeCodeLab, o maior ganho veio do audit inicial e do screenshot em 375px. Eles revelaram problemas de espaço no CTA, focus do formulário e contraste em dark mode antes que virassem outra rodada de limpeza de className.

#Claude Code #Tailwind CSS #CSS #Design #Frontend
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.