Pengantar Headless UI
Pahami konsep komponen headless, pasang @headlessui/react, dan jelajahi komponen yang tersedia, termasuk Menu, Dialog, dan Listbox.
Pengantar Headless UI adalah pelajaran Tailwind CSS Academy gratis di CoddyKit. Ini adalah pelajaran 1 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.
Apa Itu Komponen Headless?
Komponen headless menyediakan perilaku, pengelolaan status, dan aksesibilitas tanpa gaya visual bawaan. Komponen ini menyediakan semua navigasi papan ketik, atribut ARIA, dan logika interaksi — tetapi menyerahkan seluruh tampilan visual kepada Anda. Ini merupakan kebalikan dari pustaka komponen bergaya seperti Bootstrap, yang menggabungkan perilaku dan tampilan. Komponen headless memungkinkan Anda menerapkan kelas Tailwind sendiri sekaligus memperoleh aksesibilitas tanpa perlu membangunnya dari awal.
Memperkenalkan Headless UI
Headless UI adalah pustaka komponen UI yang sepenuhnya tanpa gaya dan mudah diakses, yang dibuat oleh tim Tailwind Labs. Pustaka ini menyediakan komponen seperti Menu (menu tarik-turun), Dialog (dialog modal), Listbox (menu pilihan), Combobox (pelengkapan otomatis), Switch (sakelar), Disclosure (akordeon), dan Tabs. Semua persyaratan aksesibilitas — peran ARIA, navigasi papan ketik, dan pengelolaan fokus — ditangani secara internal.
# Install for React
npm install @headlessui/react
# Install for Vue
npm install @headlessui/vue
# Available components:
# Menu, Dialog, Listbox, Combobox,
# Switch, Disclosure, Popover, RadioGroup,
# Tab (Tabs, TabGroup, TabList, TabPanel)
import { Menu, Dialog, Listbox } from '@headlessui/react';Mengapa Headless UI dengan Tailwind?
Headless UI dirancang dengan mempertimbangkan Tailwind CSS — keduanya dibuat oleh tim yang sama. Setiap komponen menerima properti className dan menyediakan properti render yang memberi Anda informasi status (seperti open atau active) untuk mengatur kelas Tailwind kondisional. Berbeda dari pustaka komponen yang menghambat gaya kustom Anda, komponen Headless UI adalah kanvas kosong yang mengharapkan Anda menghiasnya dengan utilitas Tailwind.
import { Switch } from '@headlessui/react';
import { useState } from 'react';
function ToggleSwitch() {
const [enabled, setEnabled] = useState(false);
return (
<Switch
checked={enabled}
onChange={setEnabled}
className={cn(
'relative inline-flex h-6 w-11 items-center rounded-full transition-colors',
enabled ? 'bg-blue-600' : 'bg-gray-200'
)}
>
<span className={cn(
'inline-block h-4 w-4 transform rounded-full bg-white transition-transform',
enabled ? 'translate-x-6' : 'translate-x-1'
)} />
</Switch>
);
}Komponen Menu
Komponen Menu membuat menu tarik-turun yang mudah diakses dengan navigasi papan ketik. Komponen ini tersusun dari Menu.Button (pemicu), Menu.Items (panel menu tarik-turun), dan Menu.Item (setiap opsi). Headless UI secara otomatis menangani pembukaan dan penutupan saat diklik, penutupan saat mengeklik di luar, serta navigasi dengan tombol panah pada papan ketik. Anda dapat memberi gaya pada setiap bagian menggunakan kelas Tailwind.
import { Menu } from '@headlessui/react';
function UserMenu() {
return (
<Menu as='div' className='relative'>
<Menu.Button className='flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-gray-100'>
<img src='/avatar.png' className='h-8 w-8 rounded-full' alt='User' />
<span className='text-sm font-medium'>John Doe</span>
</Menu.Button>
<Menu.Items className='absolute right-0 mt-2 w-48 rounded-xl bg-white shadow-lg ring-1 ring-black/5 focus:outline-none'>
<div className='p-1'>
<Menu.Item>
{({ active }) => (
<button className={cn('w-full text-left px-3 py-2 text-sm rounded-lg', active && 'bg-gray-100')}>
Profile
</button>
)}
</Menu.Item>
</div>
</Menu.Items>
</Menu>
);
}Properti Render untuk Gaya Berbasis Status
Komponen Headless UI mengekspos status internalnya melalui properti render. Misalnya, Menu.Item menyediakan nilai boolean active yang menunjukkan apakah item sedang berfokus atau diarahkan kursor. Menu.Button mengekspos open. Nilai boolean ini menggerakkan kelas Tailwind kondisional Anda, sehingga menciptakan perbedaan visual antarstatus tanpa perlu menulis penangan peristiwa JavaScript sendiri.
// Render props expose internal state
<Menu.Button>
{({ open }) => (
<span className={cn(
'flex items-center gap-2 px-4 py-2 rounded-lg',
open ? 'bg-blue-50 text-blue-600' : 'text-gray-700 hover:bg-gray-100'
)}>
Options
<ChevronDownIcon className={cn(
'h-4 w-4 transition-transform',
open && 'rotate-180'
)} />
</span>
)}
</Menu.Button>
// Menu.Item with active state
<Menu.Item>
{({ active, disabled }) => (
<button className={cn(
'w-full px-3 py-2 text-sm text-left rounded',
active && 'bg-blue-600 text-white',
disabled && 'opacity-50 cursor-not-allowed'
)}>
Edit
</button>
)}
</Menu.Item>Komponen Dialog
Komponen Dialog membuat modal yang sepenuhnya mudah diakses, dengan penguncian fokus bawaan dan penanganan tombol Escape. Saat dibuka, fokus papan ketik secara otomatis dipindahkan ke dalam dialog dan dibatasi di dalamnya hingga dialog ditutup. Dialog.Panel berisi konten modal, sedangkan Dialog.Overlay menyediakan lapisan latar belakang. Anda menerapkan semua gaya visual menggunakan Tailwind.
import { Dialog } from '@headlessui/react';
function ConfirmModal({ isOpen, onClose }) {
return (
<Dialog open={isOpen} onClose={onClose} className='relative z-50'>
{/* Backdrop */}
<div className='fixed inset-0 bg-black/40' aria-hidden='true' />
{/* Center the panel */}
<div className='fixed inset-0 flex items-center justify-center p-4'>
<Dialog.Panel className='bg-white rounded-2xl shadow-xl max-w-md w-full p-6'>
<Dialog.Title className='text-lg font-semibold text-gray-900'>
Confirm Action
</Dialog.Title>
<Dialog.Description className='mt-2 text-sm text-gray-600'>
Are you sure you want to continue?
</Dialog.Description>
<div className='mt-6 flex gap-3 justify-end'>
<button onClick={onClose} className='px-4 py-2 text-sm rounded-lg border'>Cancel</button>
<button className='px-4 py-2 text-sm rounded-lg bg-blue-600 text-white'>Confirm</button>
</div>
</Dialog.Panel>
</div>
</Dialog>
);
}Komponen Disclosure
Komponen Disclosure menerapkan pola akordeon atau tampilkan/sembunyikan yang mudah diakses. Komponen ini menyediakan Disclosure.Button (sakelar) dan Disclosure.Panel (konten yang dapat diperluas). Headless UI menangani atribut aria-expanded pada tombol dan secara otomatis mengaitkannya dengan panel. Komponen ini sangat cocok untuk bagian FAQ, item navigasi yang dapat diciutkan, dan panel pengaturan.
import { Disclosure } from '@headlessui/react';
function FAQItem({ question, answer }) {
return (
<Disclosure as='div' className='border-b border-gray-200 py-4'>
{({ open }) => (
<>
<Disclosure.Button className='flex w-full justify-between items-center text-left'>
<span className='font-medium text-gray-900'>{question}</span>
<ChevronDownIcon className={cn(
'h-5 w-5 text-gray-500 transition-transform',
open && 'rotate-180'
)} />
</Disclosure.Button>
<Disclosure.Panel className='mt-3 text-sm text-gray-600 leading-relaxed'>
{answer}
</Disclosure.Panel>
</>
)}
</Disclosure>
);
}Komponen Listbox
Komponen Listbox merupakan alternatif yang mudah diakses untuk elemen native <select>, dengan navigasi papan ketik lengkap dan kepatuhan terhadap ARIA, sekaligus dapat diberi gaya sepenuhnya menggunakan Tailwind. Gunakan komponen ini saat Anda memerlukan item opsi bergaya kustom dengan gambar, ikon, atau tata letak kompleks yang tidak dapat dirender oleh select native. Listbox.Options dan Listbox.Option menyusun daftar menu tarik-turun.
import { Listbox } from '@headlessui/react';
const people = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
function PersonSelect({ value, onChange }) {
return (
<Listbox value={value} onChange={onChange}>
<div className='relative'>
<Listbox.Button className='w-full rounded-lg border border-gray-300 bg-white px-4 py-2 text-left text-sm'>
{value.name}
</Listbox.Button>
<Listbox.Options className='absolute z-10 mt-1 w-full rounded-xl bg-white shadow-lg ring-1 ring-black/5'>
{people.map(person => (
<Listbox.Option key={person.id} value={person}>
{({ active, selected }) => (
<div className={cn('px-4 py-2 text-sm cursor-pointer', active && 'bg-blue-50')}>
{selected && <CheckIcon className='inline h-4 w-4 mr-2 text-blue-600' />}
{person.name}
</div>
)}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</Listbox>
);
}Komponen Tabs
Komponen Tab di Headless UI membuat antarmuka tab yang aksesibel dengan peran ARIA yang tepat, navigasi keyboard (tombol panah untuk berpindah tab), dan pengelolaan status aktif secara otomatis. Gabungkan Tab.Group, Tab.List, Tab, Tab.Panels, dan Tab.Panel — Headless UI menghubungkan semuanya, sedangkan Tailwind menyediakan tampilan visualnya.
import { Tab } from '@headlessui/react';
function TabbedContent() {
return (
<Tab.Group>
<Tab.List className='flex gap-1 rounded-xl bg-gray-100 p-1'>
{['Overview', 'Analytics', 'Settings'].map(tab => (
<Tab
key={tab}
className={({ selected }) => cn(
'flex-1 rounded-lg py-2 text-sm font-medium transition-colors',
selected
? 'bg-white text-blue-700 shadow'
: 'text-gray-600 hover:text-gray-900'
)}
>
{tab}
</Tab>
))}
</Tab.List>
<Tab.Panels className='mt-4'>
<Tab.Panel className='p-4 rounded-xl bg-white'><p>Overview content</p></Tab.Panel>
<Tab.Panel className='p-4 rounded-xl bg-white'><p>Analytics content</p></Tab.Panel>
<Tab.Panel className='p-4 rounded-xl bg-white'><p>Settings content</p></Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
}Jaminan Aksesibilitas Headless UI
Headless UI menyediakan implementasi aksesibilitas yang telah diuji dan siap digunakan dalam produksi, yang akan membutuhkan banyak usaha jika Anda menulisnya sendiri dengan benar. Dialog mengunci fokus di dalam modal, Menu menerapkan pola kotak kombo/menu ARIA dengan peran yang tepat, dan Listbox mengikuti pola Listbox ARIA. Semua ini telah diverifikasi berdasarkan ARIA Authoring Practices Guide, sehingga Anda dapat mempercayai lapisan aksesibilitasnya tanpa menulis satu atribut ARIA pun sendiri.
<!-- What Headless UI generates automatically -->
<!-- For Menu.Button -->
<button
id='headlessui-menu-button-1'
type='button'
aria-haspopup='true'
aria-expanded='true'
aria-controls='headlessui-menu-items-2'
>
Options
</button>
<!-- For Menu.Items -->
<ul
id='headlessui-menu-items-2'
role='menu'
aria-labelledby='headlessui-menu-button-1'
tabindex='-1'
>
<li role='menuitem'>...</li>
</ul>
<!-- All generated automatically — no manual ARIA needed -->Menggabungkan Komponen Headless UI
Komponen Headless UI dapat digabungkan untuk membangun pola UI yang kompleks. Halaman pengaturan dapat menggabungkan grup Tab untuk navigasi, sakelar Switch untuk preferensi, dan Dialog untuk modal konfirmasi — semuanya dalam tampilan yang sama. Setiap komponen menangani aksesibilitasnya sendiri secara terpisah, sementara kelas Tailwind menyatukan gaya visualnya. Pendekatan komposisi ini memungkinkan Anda membangun antarmuka aksesibel yang canggih dengan sedikit JavaScript khusus.
import { Tab, Switch, Dialog } from '@headlessui/react';
// Settings page combining multiple Headless UI components
function SettingsPage() {
return (
<Tab.Group>
<Tab.List class='flex gap-1 border-b border-gray-200 mb-6'>
<Tab class={({ selected }) =>
cn('px-4 py-2 text-sm font-medium border-b-2 -mb-px',
selected ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500')
}>Profile</Tab>
<Tab class={({ selected }) =>
cn('px-4 py-2 text-sm font-medium border-b-2 -mb-px',
selected ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500')
}>Notifications</Tab>
</Tab.List>
<Tab.Panels>
<Tab.Panel>{/* Profile settings with Switch toggles */}</Tab.Panel>
<Tab.Panel>{/* Notification settings */}</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
}Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Tailwind CSS Mastery dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini Anda telah mempelajari bahwa Headless UI menyediakan perilaku dan aksesibilitas tanpa gaya visual, render props mengekspos status internal (aktif, terbuka, dipilih) untuk kelas Tailwind bersyarat, dan komponen seperti Menu, Dialog, Disclosure, Listbox, dan Tab mencakup pola UI aksesibel yang paling umum. Selanjutnya, kita akan menata menu tarik-turun Headless UI dengan Tailwind secara mendetail.
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 “Pengantar Headless UI” gratis?
Ya — teks lengkap “Pengantar Headless UI” 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 “Pengantar Headless UI”?
Pahami konsep komponen headless, pasang @headlessui/react, dan jelajahi komponen yang tersedia, termasuk Menu, Dialog, dan Listbox. 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 1 dari 4.
Berapa lama pelajaran “Pengantar Headless UI” 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
- Pengantar Headless UI
- Menata Menu dan Dropdown Headless
- Membangun Dialog yang Aksesibel
- Transisi dengan Headless UI