Tabs Component
CSS-only Tailwind CSS tabs with border, lifted, boxed, and pill style variants. Active state and sizes, no JavaScript required. WCAG AA accessible, works with Django, HTMX, Laravel, React, and any stack.
Komponen tab mengatur konten menjadi beberapa bagian terpisah sehingga pengguna dapat beralih di antara keduanya tanpa meninggalkan halaman. Dibangun dengan HTML semantik dan pola masukan radio, tab menyediakan navigasi intuitif untuk mengelompokkan informasi terkait. Sistem tab Frutjam mendukung berbagai ukuran, gaya, dan arah tata letak—hanya CSS atau dikontrol JavaScript—sehingga ideal untuk dasbor, dokumentasi, dan antarmuka tab.
Hanya CSS, tidak diperlukan JavaScript. WCAG AA dapat diakses dan tidak memiliki kerangka kerja — bekerja dengan Django, HTMX, Laravel, React, dan tumpukan apa pun.
| Kelas | Jenis | Keterangan |
|---|---|---|
| tabs | Basis | Wadah untuk sekelompok input tab dan panel konten |
| tab | Pengubah | Masukan radio tab individual |
| tab-content | Pengubah | Panel konten terkait dengan tab |
| tab-active | Pengubah | Memaksa status aktif/dipilih pada tab (untuk tab yang dikontrol JS) |
| tab-disabled | Pengubah | Menonaktifkan tampilan tab |
| tabs-underline | Gaya | Garis bawahi gaya indikator |
| tabs-lifted | Gaya | Gaya tab terangkat seperti kartu |
| tabs-box | Gaya | Tab bergaya pil kotak |
| tabs-vertical | Pengubah | Tata letak tab vertikal dengan tab di kolom sebelah kiri |
| tabs-end | Pengubah | Sejajarkan baris tab ke akhir (tepat di LTR) |
| tabs-bottom | Pengubah | Tempatkan tab di bawah panel konten |
| tabs-xs | Ukuran | Bantalan tab ekstra kecil |
| tabs-sm | Ukuran | Bantalan tab kecil |
| tabs-md | Ukuran | Bantalan tab sedang (default) |
| tabs-lg | Ukuran | Bantalan tab besar |
| tabs-xl | Ukuran | Bantalan tab ekstra besar |
Penggunaan Dasar
Tab default menggunakan gaya garis bawah aktif sederhana dengan input radio. Setiap masukan tab dipasangkan dengan panel tab-content tepat setelahnya.
Overview content: a high-level summary of features, metrics, or status. This panel is visible by default.
Details content: in-depth information such as configuration options, data breakdown, or extended documentation.
Activity content: a timeline, event log, or recent changes relevant to this section.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <div class="tabs"> <input type="radio" name="tabs-basic" class="tab" aria-label="Overview" checked> <div class="tab-content pt-4"> <p>Overview content: a high-level summary of features, metrics, or status. This panel is visible by default.</p> </div> <input type="radio" name="tabs-basic" class="tab" aria-label="Details"> <div class="tab-content pt-4"> <p>Details content: in-depth information such as configuration options, data breakdown, or extended documentation.</p> </div> <input type="radio" name="tabs-basic" class="tab" aria-label="Activity"> <div class="tab-content pt-4"> <p>Activity content: a timeline, event log, or recent changes relevant to this section.</p> </div> </div> |
Gaya Tab
Gunakan tabs-underline, tabs-box, atau tabs-lifted untuk mengubah gaya visual tab strip.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <div class="tabs tabs-underline"> <input type="radio" name="style-underline" class="tab" aria-label="Overview" checked> <div class="tab-content pt-4">Underline style — a colored bottom border marks the active tab against a full-width separator line.</div> <input type="radio" name="style-underline" class="tab" aria-label="Details"> <div class="tab-content pt-4">Details panel.</div> <input type="radio" name="style-underline" class="tab" aria-label="Activity"> <div class="tab-content pt-4">Activity panel.</div> </div> <div class="tabs tabs-box"> <input type="radio" name="style-box" class="tab" aria-label="Overview" checked> <div class="tab-content pt-4">Box style — the active tab gets a raised background inside a tinted pill container.</div> <input type="radio" name="style-box" class="tab" aria-label="Details"> <div class="tab-content pt-4">Details panel.</div> <input type="radio" name="style-box" class="tab" aria-label="Activity"> <div class="tab-content pt-4">Activity panel.</div> </div> <div class="tabs tabs-lifted"> <input type="radio" name="style-lifted" class="tab" aria-label="Overview" checked> <div class="tab-content p-4">Lifted style — the active tab appears as a card tab with borders that merge into the content panel below.</div> <input type="radio" name="style-lifted" class="tab" aria-label="Details"> <div class="tab-content p-4">Details panel.</div> <input type="radio" name="style-lifted" class="tab" aria-label="Activity"> <div class="tab-content p-4">Activity panel.</div> </div> |
Ukuran Tab
Skalakan padding tab dari tabs-xs ke tabs-xl agar sesuai dengan kepadatan tata letak Anda.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <div class="tabs tabs-underline tabs-xs"> <input type="radio" name="size-xs" class="tab" aria-label="Extra Small" checked> <div class="tab-content pt-3">Extra small tabs</div> <input type="radio" name="size-xs" class="tab" aria-label="Tab 2"> <div class="tab-content pt-3">Content</div> </div> <div class="tabs tabs-underline tabs-sm"> <input type="radio" name="size-sm" class="tab" aria-label="Small" checked> <div class="tab-content pt-3">Small tabs</div> <input type="radio" name="size-sm" class="tab" aria-label="Tab 2"> <div class="tab-content pt-3">Content</div> </div> <div class="tabs tabs-underline tabs-md"> <input type="radio" name="size-md" class="tab" aria-label="Medium" checked> <div class="tab-content pt-3">Medium tabs (default)</div> <input type="radio" name="size-md" class="tab" aria-label="Tab 2"> <div class="tab-content pt-3">Content</div> </div> <div class="tabs tabs-underline tabs-lg"> <input type="radio" name="size-lg" class="tab" aria-label="Large" checked> <div class="tab-content pt-3">Large tabs</div> <input type="radio" name="size-lg" class="tab" aria-label="Tab 2"> <div class="tab-content pt-3">Content</div> </div> <div class="tabs tabs-underline tabs-xl"> <input type="radio" name="size-xl" class="tab" aria-label="Extra Large" checked> <div class="tab-content pt-3">Extra large tabs</div> <input type="radio" name="size-xl" class="tab" aria-label="Tab 2"> <div class="tab-content pt-3">Content</div> </div> |
Tab dengan Tombol
Gabungkan tab dengan btn untuk merender tab sebagai tombol bergaya. Kelas btn mengambil alih warna dan radius batas sementara logika pemilihan tab dipertahankan.
Home — your primary landing panel with quick access to key actions and a summary view.
Profile — manage personal information, preferences, and account details.
Settings — configure notifications, privacy options, and connected integrations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <div class="tabs gap-2"> <input type="radio" name="btn-tabs" class="tab btn btn-sm" aria-label="Home" checked> <div class="tab-content pt-4"> <p>Home — your primary landing panel with quick access to key actions and a summary view.</p> </div> <input type="radio" name="btn-tabs" class="tab btn btn-sm" aria-label="Profile"> <div class="tab-content pt-4"> <p>Profile — manage personal information, preferences, and account details.</p> </div> <input type="radio" name="btn-tabs" class="tab btn btn-sm" aria-label="Settings"> <div class="tab-content pt-4"> <p>Settings — configure notifications, privacy options, and connected integrations.</p> </div> </div> |
Tab yang Dinonaktifkan
Tambahkan atribut tab-disabled dan disabled untuk mencegah interaksi dengan tab.
1 2 3 4 5 6 7 8 9 10 | <div class="tabs tabs-underline"> <input type="radio" name="disabled-tabs" class="tab" aria-label="Available" checked> <div class="tab-content pt-4">This tab is active and accessible.</div> <input type="radio" name="disabled-tabs" class="tab tab-disabled" aria-label="Unavailable" disabled> <div class="tab-content pt-4">This content is not reachable.</div> <input type="radio" name="disabled-tabs" class="tab" aria-label="Another"> <div class="tab-content pt-4">Another available tab panel.</div> </div> |
Tab Vertikal
tabs-vertical beralih ke tata letak kotak dengan tab di kolom sebelah kiri dan konten memenuhi kolom sebelah kanan. Garis pemisah tinggi penuh secara otomatis ditambahkan antar kolom.
General Settings
Manage your display name, language preference, and time zone.
Security
Update your password, enable two-factor authentication, and review active sessions.
Notifications
Choose which events trigger email, push, or in-app notifications.
Billing
View invoices, update your payment method, and manage your subscription plan.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <div class="tabs tabs-vertical"> <input type="radio" name="vertical" class="tab" aria-label="General" checked> <div class="tab-content px-6 py-2"> <h3 class="font-semibold mb-1">General Settings</h3> <p>Manage your display name, language preference, and time zone.</p> </div> <input type="radio" name="vertical" class="tab" aria-label="Security"> <div class="tab-content px-6 py-2"> <h3 class="font-semibold mb-1">Security</h3> <p>Update your password, enable two-factor authentication, and review active sessions.</p> </div> <input type="radio" name="vertical" class="tab" aria-label="Notifications"> <div class="tab-content px-6 py-2"> <h3 class="font-semibold mb-1">Notifications</h3> <p>Choose which events trigger email, push, or in-app notifications.</p> </div> <input type="radio" name="vertical" class="tab" aria-label="Billing"> <div class="tab-content px-6 py-2"> <h3 class="font-semibold mb-1">Billing</h3> <p>View invoices, update your payment method, and manage your subscription plan.</p> </div> </div> |
Tab di Bawah
tabs-bottom membalik tata letak sehingga konten muncul di atas setrip tab, berguna untuk bilah navigasi gaya seluler atau bilah alat bawah.
Feed — latest posts and updates from people you follow.
Explore — discover trending topics, creators, and recommended content.
Saved — articles and posts you bookmarked for later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <div class="tabs tabs-bottom tabs-underline"> <input type="radio" name="bottom-tabs" class="tab" aria-label="Feed" checked> <div class="tab-content pb-4"> <p>Feed — latest posts and updates from people you follow.</p> </div> <input type="radio" name="bottom-tabs" class="tab" aria-label="Explore"> <div class="tab-content pb-4"> <p>Explore — discover trending topics, creators, and recommended content.</p> </div> <input type="radio" name="bottom-tabs" class="tab" aria-label="Saved"> <div class="tab-content pb-4"> <p>Saved — articles and posts you bookmarked for later.</p> </div> </div> |
Tab Disejajarkan ke Akhir
tabs-end mendorong tab strip ke kanan (akhir) penampung, berguna untuk navigasi sekunder atau menu tindakan.
1 2 3 4 5 6 7 8 9 10 | <div class="tabs tabs-underline tabs-end"> <input type="radio" name="end-tabs" class="tab" aria-label="Week" checked> <div class="tab-content pt-4">Weekly view — aggregated metrics for the past 7 days.</div> <input type="radio" name="end-tabs" class="tab" aria-label="Month"> <div class="tab-content pt-4">Monthly view — trend analysis over the past 30 days.</div> <input type="radio" name="end-tabs" class="tab" aria-label="Year"> <div class="tab-content pt-4">Yearly view — annual summary and year-over-year comparison.</div> </div> |
Tab yang dikontrol JavaScript
Untuk pola non-radio (misalnya tautan jangkar, konten dinamis), tambahkan tab-active ke tab yang dipilih di JavaScript. tab-content yang dipasangkan ditampilkan melalui pemilih .tab-active + .tab-content.
tab-active.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <div class="tabs tabs-box" id="js-tabs"> <button class="tab tab-active" data-tab="0">Dashboard</button> <div class="tab-content pt-4">Dashboard panel — visible because this tab has <code>tab-active</code>.</div> <button class="tab" data-tab="1">Reports</button> <div class="tab-content pt-4">Reports panel.</div> <button class="tab" data-tab="2">Integrations</button> <div class="tab-content pt-4">Integrations panel.</div> </div> <script> document.querySelectorAll('#js-tabs .tab').forEach(tab => { tab.addEventListener('click', () => { document.querySelectorAll('#js-tabs .tab').forEach(t => t.classList.remove('tab-active')); tab.classList.add('tab-active'); }); }); </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import { useTabs } from 'frutjam/react' export default function TabsDemo() { const tabs = useTabs(0) return ( <div className="tabs tabs-box"> <button {...tabs.tabProps(0)}>Dashboard</button> <div {...tabs.panelProps(0)} className="tab-content pt-4">Dashboard panel.</div> <button {...tabs.tabProps(1)}>Reports</button> <div {...tabs.panelProps(1)} className="tab-content pt-4">Reports panel.</div> <button {...tabs.tabProps(2)}>Integrations</button> <div {...tabs.panelProps(2)} className="tab-content pt-4">Integrations panel.</div> </div> ) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <script setup> import { ref } from 'vue' const active = ref(0) </script> <template> <div class="tabs tabs-box"> <button v-for="(label, i) in ['Dashboard', 'Reports', 'Integrations']" :key="i" class="tab" :class="{ 'tab-active': active === i }" :aria-selected="active === i" role="tab" @click="active = i" ></button> <div class="tab-content pt-4" :hidden="active !== 0">Dashboard panel.</div> <div class="tab-content pt-4" :hidden="active !== 1">Reports panel.</div> <div class="tab-content pt-4" :hidden="active !== 2">Integrations panel.</div> </div> </template> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <script> let active = $state(0) const labels = ['Dashboard', 'Reports', 'Integrations'] </script> <div class="tabs tabs-box"> {#each labels as label, i} <button class="tab" class:tab-active={active === i} aria-selected={active === i} role="tab" onclick={() => active = i} >{label}</button> <div class="tab-content pt-4" hidden={active !== i}>{label} panel.</div> {/each} </div> |