Episode ini membahas cara membangun komponen accessible memakai Headless UI, Radix, dan Tailwind UI, serta menyusun dokumentasi dan pengembangan komponen dengan Storybook yang terintegrasi dengan Tailwind.

Komponen interaktif seperti dialog, menu, dan tabs menyimpan banyak jebakan aksesibilitas: fokus trap, keyboard navigation, dan ARIA. Menulisnya dari nol berulang kali itu boros dan rawan bug. Episode 19 membahas pendekatan headless UI: komponen logika tanpa gaya, yang lalu di-styling dengan Tailwind.
Pola ini memisahkan dua hal: perilaku yang disediakan library headless, dan tampilan yang sepenuhnya di tangan kalian lewat utility class. Hasilnya komponen accessible dengan gaya yang sepenuhnya custom — dan Tailwind UI serta Storybook menyempurnakan alur kerjanya.
Headless UI dari Tailwind Labs menyediakan komponen tanpa gaya: menu, listbox, dialog, disclosure, dan lainnya. Memasangnya:
npm install @headlessui/reactLalu styling dilakukan murni dengan utility Tailwind:
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
export function Dropdown() {
return (
<Menu>
<MenuButton className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
Opsi
</MenuButton>
<MenuItems className="absolute mt-1 w-40 rounded border border-gray-200 bg-white p-1 shadow-lg">
<MenuItem>
<button className="block w-full rounded px-3 py-1 text-left hover:bg-gray-100">
Edit
</button>
</MenuItem>
<MenuItem>
<button className="block w-full rounded px-3 py-1 text-left hover:bg-gray-100">
Hapus
</button>
</MenuItem>
</MenuItems>
</Menu>
);
}MenuButton dan MenuItem menangani keyboard navigation, fokus, dan ARIA secara otomatis — kalian hanya bertanggung jawab atas tampilan lewat class seperti hover:bg-gray-100.
Radix UI adalah koleksi primitives tak bergaya yang lebih granular. Pola pemakaiannya sama: bungkus dengan class Tailwind. Pilihan antara Headless UI dan Radix biasanya soal selera dan kebutuhan — keduanya menghasilkan komponen accessible tanpa gaya bawaan.
Tailwind UI adalah kumpulan komponen premium berbayar dari Tailwind Labs. Komponennya ditulis penuh dengan utility class — tanpa dependency lain. Kalian menyalin markup-nya lalu menyesuaikan:
<div class="flex items-center gap-4 rounded-lg bg-white p-6 shadow">
<img src="avatar.png" alt="Avatar" class="h-12 w-12 rounded-full" />
<div>
<p class="text-sm font-medium text-gray-900">Nama Pengguna</p>
<p class="text-sm text-gray-500">Deskripsi singkat profil.</p>
</div>
</div>Keunggulan Tailwind UI: konsisten, sudah responsive, dan langsung di-customize. Kelemahan: berbayar dan tidak mencakup komponen dengan logika kompleks — untuk itu tetap butuh Headless UI atau Radix.
Storybook adalah tempat mengembangkan dan mendokumentasikan komponen secara terisolasi. Inisialisasi:
npx storybook@latest initAgar Tailwind berfungsi di Storybook, import CSS global lewat decorator:
import "../src/styles.css";
import type { Preview } from "@storybook/react";
const preview: Preview = {
decorators: [
(Story) => (
<div className="p-4">
<Story />
</div>
),
],
};
export default preview;Setelah itu setiap komponen punya stories sendiri:
import { Button } from "./Button";
export const Primary = {
args: { variant: "primary", children: "Simpan" },
};
export const Ghost = {
args: { variant: "ghost", children: "Batal" },
};Stories ini bukan sekadar dokumentasi — episode 20 akan memakainya sebagai dasar visual regression testing.
Tip
Kombinasi terbaik untuk library komponen: Headless UI atau Radix untuk logika, utility Tailwind untuk tampilan, Storybook untuk pengembangan, dan CVA dari episode 15 untuk API variants. Empat elemen ini menjadi fondasi komponen yang accessible, konsisten, dan terdokumentasi.
Episode 19 membangun fondasi library komponen: komponen accessible dengan Headless UI dan Radix, gaya siap pakai dari Tailwind UI, serta dokumentasi dan pengembangan terisolasi dengan Storybook.
Inti yang harus dibawa pulang:
Di episode 20 selanjutnya kita akan membahas testing, observability & monitoring — visual regression testing dengan Playwright dan Chromatic, pemantauan performa memakai Lighthouse dan Web Vitals, serta mencegah regresi CSS di CI.