Tips & Tricks (Diperbarui: 2/6/2026)

Tips Tailwind CSS dengan Claude Code: Panduan UI yang Stabil

Praktik Tailwind CSS dengan Claude Code: design token, responsive UI, dark mode, komponen, safelist, dan visual checks.

Tips Tailwind CSS dengan Claude Code: Panduan UI yang Stabil

Tailwind CSS memudahkan kita membangun UI dengan utility class kecil seperti p-4, grid, text-sm, dan rounded-lg. Claude Code mempercepat proses itu karena bisa membaca codebase, mengedit file, menjalankan command, dan membantu review. Namun jika instruksinya hanya “buat tampilannya lebih bagus”, hasilnya sering menjadi className panjang, warna tidak konsisten, layout mobile rusak, dark mode kurang kontras, atau class dinamis hilang dari CSS produksi.

Artikel ini menjelaskan workflow praktis untuk memakai Claude Code bersama Tailwind CSS. Kita akan membahas design token, responsive utilities, ekstraksi komponen, cara menghindari class soup, dark mode, forms/buttons/cards, safelist dan content scanning, serta visual checks dengan Playwright. Contoh memakai React + TypeScript, tetapi pola review-nya tetap berguna untuk Astro, Next.js, Remix, Vite, atau stack lain.

Referensi resmi yang dipakai adalah Tailwind Theme variables, Responsive design, Dark mode, Detecting classes in source files, dan Adding custom styles. Untuk React dengan TypeScript, lihat React TypeScript guide. Untuk Claude Code, gunakan Claude Code docs. Untuk screenshot comparison, lihat Playwright Visual comparisons.

Kalau prompt Anda masih terlalu umum, baca dulu tips prompt yang lebih baik. Jika targetnya pengalaman mobile penuh, hubungkan juga dengan panduan PWA.

Mulai dari Audit, Bukan Rewrite

Jangan langsung meminta Claude Code mengubah file. Tailwind UI biasanya rusak karena keputusan kecil yang tersebar: warna, spacing, breakpoint, dark mode, CTA, iklan, dan code block. Minta Claude Code membuat laporan dulu.

Periksa penggunaan Tailwind CSS di repository ini. Jangan edit file dulu.
Buat laporan untuk:

- Design token yang sudah ada untuk warna, spacing, radius, shadow, typography
- React component dengan className terlalu panjang
- Layout yang mungkin rusak pada 375px, 768px, dan 1440px
- Bagian yang sudah/belum mendukung dark mode
- Style berulang pada form, button, card, dan badge
- Dynamic Tailwind class yang berisiko tidak masuk CSS produksi
- Visual check yang sudah ada: Playwright, Storybook, atau manual browser check

Di ClaudeCodeLab, Masa pernah memperbaiki spacing card dari desktop saja. Hasilnya, CTA di akhir artikel dan slot iklan terlalu rapat pada mobile. Tailwind class memang kecil, tetapi dampaknya bisa sampai ke conversion path.

Satukan Design Token

Design token adalah nama untuk nilai dasar desain: warna, jarak, font, radius, shadow, dan breakpoint. Tailwind CSS v4 memakai pendekatan CSS-first lewat @theme, sehingga token seperti --color-brand-600 bisa dipakai sebagai utility bg-brand-600. Pada proyek lama yang masih memakai tailwind.config.ts, prinsipnya sama: simpan nilai di 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);
}

Instruksi yang baik untuk Claude Code: “Gunakan token brand, surface, dan danger yang sudah ada. Tambahkan @theme hanya jika nilai baru akan dipakai ulang.” Ini lebih aman daripada “pilih warna biru yang lebih bagus,” karena nanti bisa muncul campuran blue, sky, dan indigo.

Responsive Utility Harus Mobile-First

Tailwind bersifat mobile-first. Class dasar berlaku untuk layar kecil, lalu sm:, md:, dan lg: menambahkan perubahan untuk layar lebih lebar. Kesalahan umum adalah membuat desktop grid dulu, lalu menambal mobile setelah rusak.

Perbaiki product grid dengan Tailwind CSS.
Syarat:
- 375px: 1 kolom, 640px+: 2 kolom, 1024px+: 3 kolom
- Gambar selalu square
- Tinggi card konsisten
- CTA button berada di bawah card
- Jangan ubah type Product props
- Setelah edit, cek screenshot mobile dan 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">
              Rp{product.price.toLocaleString("id-ID")}
            </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">
              Lihat detail
            </button>
          </div>
        </article>
      ))}
    </section>
  );
}

aspect-square menjaga rasio gambar, flex h-full flex-col membuat card stabil, dan mt-auto menaruh CTA di bawah meskipun judul produk berbeda panjang.

Kurangi Class Soup dengan Komponen

Class soup adalah className yang terlalu panjang sampai sulit dibaca. Tailwind tidak mewajibkan semua style dipindah ke CSS. Biasanya cukup extract komponen yang berulang, seperti button, card, badge, atau input.

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 ? "Memproses..." : children}
    </button>
  );
}

Minta Claude Code menjaga class sebagai string lengkap. Hindari pola bg-${color}-600 karena Tailwind scanner bisa tidak melihat class tersebut.

Dark Mode, Form, dan CTA Dicek Bersama

Dark mode bukan hanya mengganti background. Teks, border, shadow, input, error, disabled, dan focus ring harus ikut dicek. Untuk form, jangan hanya cek kondisi sukses, karena error dan disabled state sering muncul pada user sungguhan.

"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">
        Minta konsultasi
      </button>
    </form>
  );
}

Untuk review aksesibilitas, sambungkan juga dengan panduan aksesibilitas Claude Code.

Safelist dan Content Scanning

Tailwind menghasilkan CSS dari class yang terdeteksi di source files. Jika class dibuat dinamis, CSS produksi bisa tidak berisi class tersebut. Gunakan static map.

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>
  );
}

Jika class berasal dari package UI eksternal atau CMS, pakai @source atau @source inline() secara terbatas.

@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");

Visual Check dengan Screenshot

Build sukses tidak menjamin UI benar. Gunakan Playwright untuk viewport penting.

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 },
    );
  });
}

Minta Claude Code melaporkan file yang berubah, risiko, viewport yang dicek, kondisi dark mode, dan langkah manual jika Playwright belum tersedia.

Use Case dan Pitfall

Use caseTugas untuk Claude CodeFokus Tailwind
Landing pageReview hero, CTA, pricing, testimonial bersamaSpacing, heading scale, CTA
Dashboard SaaSRapikan table, filter, sidebar, empty stateDensity, overflow, sticky header
Lead formCek input, error, success, loading, disabledFocus ring, label, tap target
Content siteCek artikel, code block, iklan, CTAReading width, code scroll, internal link

Pitfall yang sering muncul: dynamic class, hanya review desktop, dark mode setengah jalan, @apply berlebihan, terlalu banyak warna mirip, form error tidak dicek, dan screenshot dilewati.

Monetisasi dan Catatan Uji

Perbaikan Tailwind sebaiknya membantu revenue path. Situs konten perlu mengecek CTA akhir artikel, produk template perlu mengecek pricing card, dan layanan tim perlu mengecek form konsultasi. ClaudeCodeLab menyediakan free Claude Code cheatsheet, products and templates, dan training or consultation.

Setelah workflow ini dicoba pada halaman ClaudeCodeLab, hasil paling terasa datang dari audit awal dan screenshot 375px. Keduanya menangkap masalah spacing CTA, focus form, dan contrast dark mode sebelum berubah menjadi pekerjaan cleanup className yang panjang.

#Claude Code #Tailwind CSS #CSS #Desain #Frontend
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.