Menghindari Konflik Kelas dengan tailwind-merge
Pahami cara kerja spesifisitas kelas Tailwind dan gunakan tailwind-merge untuk memastikan varian yang diterapkan terakhir menjadi pemenang tanpa masalah spesifisitas.
Menghindari Konflik Kelas dengan tailwind-merge adalah pelajaran Tailwind CSS Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Tailwind CSS Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Tailwind CSS Academy mencakup 4 pelajaran total.
Cara Konflik Kelas Tailwind Terjadi
Kelas utilitas Tailwind menetapkan properti CSS individual. Ketika dua kelas menargetkan properti yang sama — seperti p-4 dan p-8, atau text-blue-500 dan text-red-500 — keduanya akhirnya berada dalam daftar kelas elemen. Peramban menyelesaikan konflik menggunakan urutan cascade CSS: utilitas yang dibuat lebih akhir dalam lembar gaya Tailwind akan menang, terlepas dari urutannya dalam HTML. Tanpa tailwind-merge, hal ini membuat penggantian gaya komponen induk menjadi tidak dapat diprediksi.
<!-- Both p-4 and p-8 appear in the DOM -->
<div class="p-4 p-8">...</div>
<!-- Which padding is applied? Depends on Tailwind's
stylesheet order, not the class string order. -->
<!-- Same problem with text colors -->
<div class="text-gray-900 text-blue-500">...</div>
<!-- Will the text be gray or blue? You cannot be sure. -->Fungsi tailwind-merge
tailwind-merge adalah utilitas saat runtime yang menganalisis string kelas dan menghapus kelas Tailwind yang berkonflik, dengan mempertahankan hanya kelas terakhir dari setiap grup konflik. Utilitas ini memiliki peta internal yang mencatat utilitas Tailwind mana yang saling berkonflik — misalnya memahami bahwa p-4 dan p-8 sama-sama menetapkan padding, atau bahwa font-bold dan font-medium sama-sama menetapkan font-weight. Kelas terakhir dalam string input selalu menang.
import { twMerge } from 'tailwind-merge';
// Conflict resolution: last value wins
twMerge('p-4 p-8')
// Output: 'p-8'
twMerge('text-gray-900 text-blue-500')
// Output: 'text-blue-500'
twMerge('font-bold font-medium text-sm text-lg')
// Output: 'font-medium text-lg'
// Non-conflicting classes are kept
twMerge('flex items-center gap-4 p-4')
// Output: 'flex items-center gap-4 p-4'Instalasi dan Penggunaan Dasar
Instal tailwind-merge sebagai dependensi produksi (bukan hanya dependensi pengembangan, karena utilitas ini berjalan saat runtime). Impor twMerge dan bungkus string kelas apa pun yang mungkin mengalami konflik. Fungsi ini menerima beberapa argumen dan menggabungkan semuanya, mirip dengan cara clsx menerima beberapa argumen — sehingga mudah diterapkan pada kode yang sudah ada.
npm install tailwind-merge
import { twMerge } from 'tailwind-merge';
// Single string
const cls = twMerge('bg-blue-500 bg-red-500');
// → 'bg-red-500'
// Multiple arguments (like clsx)
const cls2 = twMerge(
'px-4 py-2 rounded', // base
'px-8', // override padding-x
'text-white'
);
// → 'py-2 rounded px-8 text-white'twMerge Memahami Grup Utilitas
tailwind-merge memahami taksonomi utilitas Tailwind secara menyeluruh. Utilitas ini mengetahui bahwa px-4 menetapkan padding horizontal, sedangkan py-2 menetapkan padding vertikal, sehingga keduanya tidak berkonflik. Utilitas ini juga mengetahui bahwa shadow-md dan shadow-lg sama-sama menetapkan properti box-shadow dan akan berkonflik. Selain itu, varian seperti hover:bg-blue-500 dan hover:bg-red-500 ditangani sebagai grup konflik terpisah dari padanan tanpa varian.
import { twMerge } from 'tailwind-merge';
// px and py don't conflict with each other
twMerge('px-4 py-2 px-8')
// → 'py-2 px-8' (px-4 removed, px-8 wins)
// Hover variants are separate groups
twMerge('hover:bg-blue-500 hover:bg-red-500 bg-white')
// → 'bg-white hover:bg-red-500'
// Shadow variants
twMerge('shadow-sm shadow-lg shadow-md')
// → 'shadow-md'
// Responsive prefixes are separate groups
twMerge('md:text-xl md:text-2xl text-sm')
// → 'text-sm md:text-2xl'Pola Pembantu cn()
Pola standar dalam proyek React/Next.js adalah menggabungkan clsx dan twMerge menjadi satu fungsi pembantu cn(). clsx menangani logika kelas kondisional dan menyaring nilai falsy; kemudian twMerge menyelesaikan konflik apa pun dalam string yang dihasilkan. Definisikan fungsi ini sekali dalam file utilitas Anda dan gunakan di mana saja — pendekatan ini digunakan oleh shadcn/ui dan sebagian besar pustaka komponen Tailwind modern.
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// Usage: conditional classes with conflict resolution
function Badge({ active, className }) {
return (
<span
className={cn(
'px-2 py-1 rounded-full text-sm font-medium',
active ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-600',
className // caller override — twMerge resolves conflicts
)}
>
Label
</span>
);
}Pola Penggantian Properti className
Kasus penggunaan utama tailwind-merge dalam komponen React adalah memungkinkan penggantian melalui properti className dengan aman. Ketika komponen memiliki gaya bawaan dan pemanggil memberikan kelas tambahan atau pengganti melalui properti className, twMerge memastikan maksud pemanggil dipenuhi. Dengan begitu, komponen benar-benar dapat disesuaikan tanpa mengharuskan pengguna berhadapan dengan spesifisitas CSS atau menggunakan !important.
// Without twMerge: caller override might not work
function Card({ className, children }) {
return (
<div className={'bg-white rounded-xl p-6 shadow ' + className}>
{children}
</div>
);
}
<Card className='bg-gray-50' /> // bg-white and bg-gray-50 both present!
// With twMerge: caller override always wins
function Card({ className, children }) {
return (
<div className={cn('bg-white rounded-xl p-6 shadow', className)}>
{children}
</div>
);
}
<Card className='bg-gray-50' /> // only bg-gray-50 (bg-white removed)Nilai Arbitrer dan twMerge
tailwind-merge juga menangani kelas nilai arbitrer yang menggunakan notasi kurung siku Tailwind. Utilitas ini mengenali dengan benar bahwa p-[10px] berkonflik dengan p-4 dan bahwa w-[300px] berkonflik dengan w-full. Hal ini penting karena nilai arbitrer umum digunakan saat merancang komponen yang memerlukan ukuran presisi yang tidak tersedia dalam skala bawaan.
import { twMerge } from 'tailwind-merge';
// Arbitrary values conflict with standard utilities
twMerge('p-4 p-[10px]')
// → 'p-[10px]' (last wins)
twMerge('w-full w-[300px]')
// → 'w-[300px]'
twMerge('text-sm text-[15px]')
// → 'text-[15px]'
// Mix of standard and arbitrary
twMerge('bg-blue-500 bg-[#2563eb]')
// → 'bg-[#2563eb]'Mengonfigurasi twMerge untuk Kelas Kustom
Secara bawaan, tailwind-merge hanya mengetahui utilitas bawaan Tailwind. Jika Anda menambahkan utilitas kustom melalui plugin atau konfigurasi, twMerge tidak akan mengetahui bahwa utilitas tersebut berkonflik dengan bawaan terkait. Gunakan extendTailwindMerge() untuk mengajarkan twMerge tentang kelas kustom Anda, sehingga penyelesaian konflik dapat berfungsi dengan benar pada kumpulan utilitas yang diperluas.
import { extendTailwindMerge } from 'tailwind-merge';
// Tell twMerge about custom text-shadow utilities
const customTwMerge = extendTailwindMerge({
extend: {
classGroups: {
'text-shadow': ['text-shadow-sm', 'text-shadow-md', 'text-shadow-lg', 'text-shadow-none']
}
}
});
// Now conflicts are resolved correctly
customTwMerge('text-shadow-sm text-shadow-lg')
// → 'text-shadow-lg'
// Update cn() to use the custom instance
export const cn = (...inputs) => customTwMerge(clsx(inputs));Pertimbangan Performa
tailwind-merge mengurai dan menyelesaikan string kelas saat runtime di peramban. Untuk sebagian besar aplikasi, proses ini sangat cepat hingga hampir tidak terasa. Namun, komponen yang merender ribuan instans (seperti daftar virtual atau sel tabel) dapat memperoleh manfaat dari penyimpanan tembolok string kelas yang telah diselesaikan. tailwind-merge menyediakan pabrik createTailwindMerge() yang memungkinkan penggunaan adaptor tembolok kustom. Untuk sebagian besar aplikasi, tembolok bawaan (yang secara internal menggunakan LRU) sudah memadai.
import { createTailwindMerge, getDefaultConfig } from 'tailwind-merge';
// Create a version with a larger cache for high-volume usage
const twMerge = createTailwindMerge(getDefaultConfig);
// For critical performance: memoize with React.useMemo
function VirtualListItem({ selected, disabled, className }) {
const itemClass = useMemo(
() => cn(
'flex items-center px-3 py-2',
selected && 'bg-blue-50',
disabled && 'opacity-50',
className
),
[selected, disabled, className]
);
return <div className={itemClass}>{/* ... */}</div>;
}Kesalahan Umum pada tailwind-merge
tailwind-merge memiliki beberapa kasus khusus yang perlu diperhatikan. Utilitas ini tidak menangani kelas CSS Modules — hanya nama utilitas Tailwind. Jika string kelas berisi kelas non-Tailwind (seperti kelas BEM kustom), twMerge meneruskannya tanpa perubahan. Selain itu, beberapa utilitas yang dibuat plugin mungkin tidak dikenali tanpa memperluas konfigurasi penggabungan. Terakhir, twMerge bekerja pada string kelas, bukan pada CSS yang dirender, sehingga tidak dapat menyelesaikan konflik yang disebabkan oleh cascade CSS di luar utilitas Tailwind.
import { twMerge } from 'tailwind-merge';
// Non-Tailwind classes pass through untouched
twMerge('card__header bg-white bg-gray-50')
// → 'card__header bg-gray-50' (custom class kept, Tailwind conflict resolved)
// CSS Modules classes (hash-based) also pass through
twMerge('styles__button_abc123 bg-blue-500 bg-red-500')
// → 'styles__button_abc123 bg-red-500'
// Unknown plugin classes (without extendTailwindMerge) pass through
twMerge('text-shadow-lg text-shadow-sm') // both kept if not configured
// → 'text-shadow-lg text-shadow-sm' (no conflict detected)Pengujian dengan tailwind-merge
Saat menulis pengujian unit untuk komponen yang menggunakan cn(), uji keluaran string kelas yang sebenarnya untuk memastikan konflik diselesaikan dengan benar. Hal ini sangat bermanfaat untuk pustaka komponen yang mengharuskan pemanggil dapat mengganti gaya bawaan secara andal. Pengujian snapshot untuk keluaran className memastikan pemfaktoran ulang di masa mendatang tidak secara tidak sengaja merusak perilaku penggantian.
// card.test.ts
import { cn } from '@/lib/utils';
import { cardVariants } from './Card';
test('caller className overrides default bg', () => {
const result = cn(cardVariants({ variant: 'white' }), 'bg-gray-50');
// bg-white from variant should be removed, bg-gray-50 should win
expect(result).not.toContain('bg-white');
expect(result).toContain('bg-gray-50');
});
test('non-conflicting classes are additive', () => {
const result = cn('p-6 rounded-xl', 'mt-4');
expect(result).toContain('p-6');
expect(result).toContain('rounded-xl');
expect(result).toContain('mt-4');
});Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Tailwind CSS Mastery dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini Anda mempelajari bahwa tailwind-merge menyelesaikan konflik utilitas Tailwind dengan mempertahankan hanya kelas terakhir dari setiap grup konflik, pembantu cn() menggabungkan clsx dan twMerge untuk menangani kelas kondisional tanpa konflik, dan extendTailwindMerge() mengajarkan pustaka ini tentang kelas dari plugin kustom. Selanjutnya, kita akan membahas Headless UI dan cara integrasinya dengan Tailwind untuk membuat komponen yang mudah diakses.
Belajar HTML dengan tutor AI — gratis
Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.
- Kursus
- 30
- Pelajaran
- 120
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Menghindari Konflik Kelas dengan tailwind-merge” gratis?
Ya — teks lengkap “Menghindari Konflik Kelas dengan tailwind-merge” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Tailwind CSS Academy, upgrade ke CoddyKit PRO. Kursus Tailwind CSS Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Menghindari Konflik Kelas dengan tailwind-merge”?
Pahami cara kerja spesifisitas kelas Tailwind dan gunakan tailwind-merge untuk memastikan varian yang diterapkan terakhir menjadi pemenang tanpa masalah spesifisitas. Kamu berlatih Tailwind CSS Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Tailwind CSS Academy?
Tidak diperlukan pengalaman sebelumnya. Tailwind CSS Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.
Berapa lama pelajaran “Menghindari Konflik Kelas dengan tailwind-merge” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Tailwind CSS Academy ini?
Ya. Setiap pelajaran Tailwind CSS Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Menyiapkan Tailwind di Next.js
- Kelas Kondisional di React
- Varian Komponen dengan CVA
- Menghindari Konflik Kelas dengan tailwind-merge