kodingup.camp

Beranda/Tailwind Mastery

Konsep Inti Utility

Modul 4 dari 164 menit bacaCore Utility Concepts

Isi modul

    Kenapa ini penting

    Setelah bisa menyusun class, kamu perlu paham "mesin" di baliknya. Kenapa p-4 sama dengan 1rem? Bagaimana kalau desain meminta nilai yang tidak ada di skala, misalnya 13px? Kenapa class yang dibuat dengan menggabungkan string di JavaScript tiba-tiba tidak muncul? Pertanyaan-pertanyaan ini sering membuat pemula frustrasi.

    Modul ini menjawabnya. Dengan memahami skala spacing, arbitrary value, state variant, important modifier, dan cara Tailwind mendeteksi class, kamu bisa memecahkan 90% masalah "kok style-nya tidak keluar?" sendiri.

    Konsep inti

    Skala spacing berbasis satu variabel

    Di v4, seluruh skala spacing diturunkan dari satu variabel tema: --spacing: 0.25rem (4px). Utility seperti p-4 dihitung sebagai calc(var(--spacing) * 4) = 1rem = 16px. Artinya, angka apa pun bisa dipakai: p-13, mt-17, w-29 semuanya valid tanpa konfigurasi tambahan. Ini berbeda dengan v3 yang hanya mengenal angka tertentu.

    Class Hitungan Hasil
    p-1 0.25rem × 1 4px
    p-4 0.25rem × 4 16px
    p-2.5 0.25rem × 2.5 10px
    p-13 0.25rem × 13 52px
    p-px nilai khusus 1px

    Analogi: skala spacing itu seperti penggaris dengan satuan "ketukan" 4px. Desainer dan developer berbicara dalam ketukan yang sama, jadi jarak antar elemen konsisten di seluruh aplikasi.

    Arbitrary value [...]

    Kalau butuh nilai yang benar-benar spesifik, gunakan kurung siku: top-[117px], bg-[#1da1f2], grid-cols-[200px_1fr]. Spasi di dalam nilai ditulis dengan garis bawah _. Untuk memakai CSS variable, v4 punya bentuk singkat dengan kurung biasa: bg-(--warna-brand) sama dengan bg-[var(--warna-brand)].

    Ada juga arbitrary property untuk properti CSS yang belum punya utility: [mask-type:luminance].

    Gunakan arbitrary value seperlunya. Kalau nilai yang sama dipakai berulang, itu tanda nilai tersebut sebaiknya menjadi token di @theme.

    State variants yang lebih kaya

    Selain hover dan focus, ada banyak variant yang menghemat JavaScript:

    Important modifier

    Kadang kamu harus mengalahkan style lain (misalnya CSS dari library pihak ketiga). Tambahkan ! di akhir class: bg-red-500! menghasilkan background-color: ... !important. Bentuk lama v3 dengan ! di depan (!bg-red-500) masih dikenali demi kompatibilitas, tetapi tulisan resmi v4 adalah di akhir. Gunakan sebagai jalan terakhir, bukan kebiasaan.

    Cara kerja deteksi class

    Tailwind tidak menjalankan kodemu. Ia hanya memindai teks file sumber dan mencari potongan yang terlihat seperti nama class, lalu membuat CSS untuk yang ditemukan. Di v4, pemindaian otomatis mencakup semua file di proyek, kecuali yang ada di .gitignore, folder node_modules, file biner, dan file CSS.

    Konsekuensinya sangat penting: nama class harus utuh di dalam kode. Kode seperti `bg-${warna}-500` tidak akan terdeteksi karena string bg-red-500 tidak pernah tertulis utuh. Solusinya, petakan nilai ke class lengkap.

    Kalau ada file di luar jangkauan otomatis (misalnya komponen dari paket di node_modules), tambahkan dengan @source "../node_modules/nama-paket";. Kamu juga bisa mengecualikan folder dengan @source not "./legacy";, atau memaksa class tertentu selalu dibuat dengan @source inline("bg-red-500 bg-green-500");.

    Contoh kode

    <!-- Skala spacing: angka bebas karena dihitung dari --spacing -->
    <div class="bg-sky-100 p-13">Padding 52px</div>
    <!-- → .p-13 { padding: calc(var(--spacing) * 13); } -->
    
    <!-- Arbitrary value: nilai spesifik dari desain -->
    <div class="top-[117px] w-[37.5%] bg-[#1da1f2] text-[15px]">Nilai khusus</div>
    
    <!-- Spasi di arbitrary value pakai garis bawah -->
    <div class="grid grid-cols-[200px_1fr] gap-4">
      <aside>Sidebar 200px</aside>
      <main>Konten sisanya</main>
    </div>
    
    <!-- CSS variable dengan sintaks singkat v4 -->
    <div style="--warna-brand: #e11d48" class="bg-(--warna-brand) p-4 text-white">Brand</div>
    
    <!-- group: anak bereaksi saat induk di-hover -->
    <a href="#" class="group block rounded-lg p-4 hover:bg-gray-100">
      <span class="font-semibold group-hover:text-indigo-600">Baca artikel</span>
      <span class="inline-block transition group-hover:translate-x-1">→</span>
    </a>
    
    <!-- peer: pesan error muncul saat input tidak valid -->
    <input type="email" class="peer rounded border px-3 py-2" placeholder="Email" />
    <p class="mt-1 hidden text-sm text-red-600 peer-invalid:block">Format email salah.</p>
    
    <!-- not-first: garis pemisah di semua item kecuali yang pertama -->
    <ul>
      <li class="py-2 not-first:border-t">Satu</li>
      <li class="py-2 not-first:border-t">Dua</li>
      <li class="py-2 not-first:border-t">Tiga</li>
    </ul>
    
    <!-- Important modifier (tanda ! di akhir) -->
    <div class="bg-teal-500 bg-red-500!">Merah menang</div>
    <!-- → .bg-red-500\! { background-color: var(--color-red-500) !important; } -->
    
    // Deteksi class: SALAH vs BENAR
    function Badge({ status }) {
      // SALAH: Tailwind tidak bisa menemukan "bg-green-500" di teks ini
      // const cls = `bg-${status === "aktif" ? "green" : "gray"}-500`;
    
      // BENAR: tulis nama class lengkap di dalam kode
      const warna = {
        aktif: "bg-green-500 text-white",
        nonaktif: "bg-gray-300 text-gray-700",
      };
      return <span className={`rounded px-2 py-1 text-xs ${warna[status]}`}>{status}</span>;
    }
    // <Badge status="aktif" /> → lencana hijau bertuliskan "aktif"
    
    /* src/style.css: mengatur sumber yang dipindai */
    @import "tailwindcss";
    
    /* Pindai komponen dari library UI di node_modules */
    @source "../node_modules/@acme/ui";
    
    /* Abaikan folder lama */
    @source not "./legacy";
    
    /* Selalu buat class ini walau tidak tertulis di mana pun */
    @source inline("bg-red-500 bg-green-500 bg-yellow-500");
    

    Kesalahan umum

    1. Membuat nama class secara dinamis. `text-${size}` tidak terdeteksi. Petakan ke string lengkap dalam objek atau gunakan @source inline(...).
    2. Memakai spasi di arbitrary value. grid-cols-[200px 1fr] dianggap dua class. Tulis grid-cols-[200px_1fr].
    3. Kebanyakan arbitrary value. Kalau text-[#1e3a8a] muncul di 20 tempat, jadikan token --color-brand di @theme.
    4. Menaburkan ! di mana-mana. Biasanya ini tanda ada masalah urutan CSS atau specificity yang seharusnya diperbaiki di akarnya.
    5. Menganggap file di node_modules ikut dipindai. Tidak. Tambahkan dengan @source.

    Latihan

    1. Mudah, Berapa piksel padding yang dihasilkan p-7 dengan --spacing default?
    2. Sedang, Buat kotak dengan lebar tepat 350px, tinggi 13rem, dan warna latar #fde68a memakai arbitrary value.
    3. Menantang, Perbaiki komponen React berikut agar class-nya terdeteksi: <div className={`text-${ukuran}`}> dengan ukuran bernilai "kecil", "sedang", atau "besar".
    Lihat solusi
    1. p-7 = 0.25rem × 7 = 1.75rem = 28px.

    2. Kotak:

    <div class="h-[13rem] w-[350px] bg-[#fde68a]">Kotak kuning</div>
    <!-- Catatan: h-52 juga menghasilkan 13rem (0.25 × 52), jadi lebih baik pakai skala -->
    
    1. Komponen yang diperbaiki:
    const ukuranClass = {
      kecil: "text-sm",
      sedang: "text-base",
      besar: "text-2xl",
    };
    
    function Teks({ ukuran = "sedang", children }) {
      return <div className={ukuranClass[ukuran]}>{children}</div>;
    }
    // <Teks ukuran="besar">Halo</Teks> → teks berukuran text-2xl
    

    Ringkasan

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.