Kenapa ini penting
Tailwind bawaan sudah sangat lengkap, tetapi setiap proyek punya kebutuhan unik: brand dengan warna dan font sendiri, efek khusus yang tidak ada di utility bawaan (misalnya scrollbar tersembunyi atau teks bergaris tepi), atau gaya dasar untuk elemen HTML tertentu. Kalau kamu tidak tahu cara memperluas Tailwind dengan benar, kamu akan tergoda menulis CSS acak di mana-mana dan kehilangan konsistensi.
Di v4, semua kustomisasi dilakukan di file CSS: @theme untuk token, @utility untuk utility baru, @custom-variant untuk variant baru, @layer untuk mengatur urutan CSS kustom, dan @plugin untuk memuat plugin JavaScript.
Konsep inti
@theme: extend vs override
- Extend (menambah): cukup tulis variabel baru.
--color-brand: #e11d48;menambah warna tanpa menghapus palet bawaan. - Override satu nilai: tulis ulang variabel yang sudah ada.
--breakpoint-sm: 36rem;mengubah nilaism:. - Override satu namespace:
--color-*: initial;lalu definisikan warna sendiri. Semua warna bawaan hilang. - Override total:
--*: initial;menghapus seluruh tema bawaan. Hanya untuk design system yang benar-benar lengkap.
Analogi: @theme itu seperti daftar menu restoran. Extend = menambah menu baru. Override satu nilai = mengganti harga satu menu. Override namespace = mengganti semua minuman. Override total = membuat menu baru dari nol.
Ada juga @theme inline { ... } untuk token yang nilainya merujuk ke variabel lain; utility akan memakai nilai rujukan itu langsung, bukan var() dari token. Ini berguna saat menghubungkan Tailwind dengan variabel dari library lain.
@utility: membuat utility sendiri
Utility kustom dibuat dengan @utility nama { ... }. Hasilnya bekerja seperti utility asli: bisa dipakai dengan variant (hover:, md:, dark:) dan diurutkan dengan benar oleh Tailwind.
Utility fungsional menerima nilai, memakai * di nama dan --value():
--value(integer)menerima angka bulat polos:tab-4.--value([integer])menerima arbitrary:tab-[13].--value(--tab-size-*)mengambil dari token tema--tab-size-*.
@custom-variant: variant sendiri
Selain untuk dark mode, kamu bisa membuat variant apa pun. Contoh: @custom-variant theme-laut (&:where([data-theme=laut] *)); lalu pakai theme-laut:bg-sky-900. Atau variant untuk perangkat dengan pointer kasar (layar sentuh): @custom-variant pointer-coarse (@media (pointer: coarse));.
@layer: mengatur urutan CSS
Tailwind v4 memakai cascade layers asli CSS: theme, base, components, utilities. Layer yang lebih belakang menang. Taruh CSS kustommu di layer yang tepat:
@layer baseuntuk gaya elemen HTML mentah (h1,a,::selection).@layer componentsuntuk class komponen (.card) yang masih boleh ditimpa oleh utility.
Karena utility berada di layer terakhir, <div class="card p-8"> akan memakai p-8 walaupun .card punya padding sendiri. Inilah alasan memakai @layer components, bukan menulis CSS lepas.
@variant di dalam CSS kustom
Di dalam CSS kustom, kamu bisa memakai variant Tailwind dengan @variant dark { ... } atau @variant hover { ... }, agar tetap konsisten dengan konfigurasi variant proyek.
@plugin
Plugin JavaScript (resmi seperti @tailwindcss/typography, @tailwindcss/forms, atau buatan komunitas) dimuat dengan @plugin "nama-paket";. Kamu juga bisa menulis plugin lokal: @plugin "./plugins/garis.js";. Untuk kebanyakan kebutuhan, @utility dan @custom-variant sudah cukup tanpa plugin.
Contoh kode
/* src/style.css */
@import "tailwindcss";
@plugin "@tailwindcss/forms"; /* reset gaya form yang rapi */
@theme {
/* Extend: tambah warna dan font */
--color-brand-50: oklch(0.97 0.02 20);
--color-brand-500: oklch(0.63 0.22 20);
--color-brand-700: oklch(0.5 0.19 22);
--font-display: "Space Grotesk", sans-serif;
/* Override satu nilai: radius 'lg' sedikit lebih besar */
--radius-lg: 0.75rem;
/* Token untuk utility fungsional di bawah */
--tab-size-kode: 2;
--tab-size-lebar: 8;
}
/* Utility statis: sembunyikan scrollbar tapi tetap bisa scroll */
@utility scrollbar-hidden {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
/* Utility statis: teks dengan garis tepi */
@utility text-outline {
-webkit-text-stroke: 1px currentColor;
color: transparent;
}
/* Utility fungsional: tab-4, tab-[13], tab-kode */
@utility tab-* {
tab-size: --value(--tab-size-*, integer, [integer]);
}
/* Variant kustom: tema alternatif via atribut data */
@custom-variant theme-laut (&:where([data-theme=laut], [data-theme=laut] *));
/* Base: gaya elemen mentah */
@layer base {
h1, h2, h3 {
font-family: var(--font-display);
}
::selection {
background: var(--color-brand-500);
color: white;
}
}
/* Components: class yang masih bisa ditimpa utility */
@layer components {
.card {
border-radius: var(--radius-lg);
background: white;
padding: --spacing(6); /* fungsi --spacing() v4 → calc(var(--spacing) * 6) */
box-shadow: var(--shadow-sm);
@variant dark {
background: var(--color-gray-800);
}
}
}
<!-- Utility kustom bekerja dengan variant seperti utility asli -->
<div class="scrollbar-hidden flex gap-3 overflow-x-auto">
<span class="shrink-0 rounded-full bg-brand-50 px-4 py-2 text-brand-700">Semua</span>
<span class="shrink-0 rounded-full bg-gray-100 px-4 py-2">Promo</span>
<span class="shrink-0 rounded-full bg-gray-100 px-4 py-2">Terlaris</span>
<span class="shrink-0 rounded-full bg-gray-100 px-4 py-2">Terbaru</span>
</div>
<!-- → bisa digeser horizontal tanpa scrollbar terlihat -->
<h1 class="text-6xl font-bold text-brand-500 text-outline hover:text-brand-500">JUDUL</h1>
<pre class="tab-kode md:tab-4"> kode dengan tab 2, menjadi 4 di md</pre>
<!-- .card dari @layer components bisa ditimpa utility -->
<div class="card p-10">Padding 2.5rem menang atas padding .card</div>
<!-- Variant kustom -->
<section data-theme="laut">
<p class="bg-white theme-laut:bg-sky-900 theme-laut:text-sky-100">Tema laut aktif</p>
</section>
Kesalahan umum
- Menulis
--color-*: initial;padahal hanya ingin menambah warna. Itu menghapus semua warna bawaan. Untuk menambah, cukup tulis variabel baru. - Membuat utility kustom dengan class biasa di luar
@utility. Class biasa tidak bisa dipakai denganhover:ataumd:dan urutannya bisa salah. Pakai@utility. - Menaruh CSS komponen di luar
@layer. CSS tanpa layer selalu menang atas semua layer, sehingga utility tidak bisa menimpanya. - Memasang plugin lewat
tailwind.config.js. Di v4 gunakan@plugindi CSS. - Nama utility kustom bentrok dengan bawaan, misalnya membuat
@utility flex. Gunakan nama yang unik.
Latihan
- Mudah, Tambahkan warna
--color-daun-500: #22c55etanpa menghapus warna bawaan, lalu buat badge yang memakainya. - Sedang, Buat utility
content-autoyang menyetelcontent-visibility: auto;dan pakai pada section panjang. - Menantang, Buat utility fungsional
garis-*yang mengatur-webkit-text-stroke-widthdengan nilai angka polos (dalam px) dan arbitrary, misalnyagaris-2dangaris-[3px].
Lihat solusi
- Warna daun:
@import "tailwindcss";
@theme {
--color-daun-500: #22c55e;
}
<span class="rounded-full bg-daun-500 px-3 py-1 text-sm text-white">Organik</span>
- Utility content-auto:
@utility content-auto {
content-visibility: auto;
}
<section class="content-auto">Section panjang di bawah lipatan</section>
- Utility fungsional garis:
@utility garis-* {
/* angka polos → px; arbitrary → nilai apa adanya */
-webkit-text-stroke-width: calc(--value(integer) * 1px);
-webkit-text-stroke-width: --value([length]);
}
<h1 class="text-7xl text-transparent garis-2 [-webkit-text-stroke-color:black]">Tebal 2px</h1>
<h1 class="text-7xl text-transparent garis-[3px] [-webkit-text-stroke-color:black]">Tebal 3px</h1>
<!-- Tailwind hanya mengeluarkan deklarasi yang --value()-nya cocok dengan nilai yang diberikan -->
Ringkasan
@theme: tambah variabel untuk extend, tulis ulang untuk override,initialuntuk menghapus namespace.@utilitymembuat utility kustom yang mendukung variant;--value()untuk utility fungsional.@custom-variantmembuat variant baru dari selector atau media query.@layer basedan@layer componentsmenjaga CSS kustom tetap bisa ditimpa utility.- Plugin JavaScript dimuat dengan
@plugin, bukan file konfigurasi JS.