Fondasi Design System
Fondasi adalah design system berbasis JavaScript dan CSS untuk membangun antarmuka pengguna yang modern dan konsisten dengan nuansa Indonesia.
Fitur Utama
- 12+ komponen UI yang siap pakai
- Didukung JavaScript (UMD) dan CSS
- Responsif dan aksesibel
- Customizable melalui variabel CSS
- Mendukung light mode dan dark mode
Struktur File
dist/fondasi.css- Full CSSdist/fondasi.min.css- Minified CSSdist/fondasi.js- Full JavaScriptdist/fondasi.min.js- Minified JavaScript
Quick Start
<link rel="stylesheet" href="fondasi.css">
<script src="fondasi.js"></script>
Installation
Ada beberapa cara untuk menginstall Fondasi ke dalam project Anda.
Cara 1: CDN
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/bideyesa/fondasi@v1.0.0/dist/fondasi.min.css">
<script src="https://cdn.jsdelivr.net/gh/bideyesa/fondasi@v1.0.0/dist/fondasi.min.js"></script>
Cara 2: NPM
npm install fondasi
import 'fondasi/dist/fondasi.css';
import { initComponents } from 'fondasi';
initComponents();
Cara 3: Download Langsung
dist/fondasi.cssdist/fondasi.min.cssdist/fondasi.jsdist/fondasi.min.js
Colors
Palette warna profesional yang menggunakan CSS custom properties. Klik untuk copy.
Brand Palette
Semantic Colors
Surface & Background
Text Colors
| Token | Value |
|---|---|
| --color-text-default | #1a1816 |
| --color-text-2 | #44403c |
| --color-text-3 | #78716c |
| --color-text-4 | #a8a29e |
| --color-text-inv | #ffffff |
Border Colors
Typography
Sistem tipografi yang menggunakan IBM Plex Sans sebagai font default dengan kontras yang jelas.
Font Families
abcdefghijklmnopqrstuvwxyz
0123456789
abcdefghijklmnopqrstuvwxyz
0123456789
return "world";
{'}'}
Font Sizes - Visual Scale
Font Weights
Line Heights
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt.
Spacing
Sistem spacing yang konsisten untuk menjaga alignment dan proximity yang tepat.
Spacing Scale - Visual
Padding Examples
Margin Examples
Gap Examples
Alert
Komponen alert untuk menampilkan pesan informasi, peringatan, kesalahan, atau konfirmasi kepada pengguna.
Class Reference
| Class | Keterangan |
|---|---|
.alert | Base alert — wajib digunakan |
.alert-info | Variant informasi (biru) |
.alert-success | Variant sukses (hijau) |
.alert-warning | Variant peringatan (kuning) |
.alert-danger | Variant bahaya / error (merah) |
.alert-brand | Variant brand navy |
.alert-icon | Wrapper ikon di dalam alert |
.alert-content | Wrapper teks (title + body) |
.alert-title | Judul alert (bold) |
.alert-dismiss | Tombol tutup alert |
.alert-sm | Ukuran kecil |
.alert-lg | Ukuran besar |
Variants
<div class="alert alert-info">Ini adalah pesan informasi.</div>
<div class="alert alert-success">Data berhasil disimpan.</div>
<div class="alert alert-warning">Periksa kembali data sebelum melanjutkan.</div>
<div class="alert alert-danger">Terjadi kesalahan. Silakan coba lagi.</div>
<div class="alert alert-brand">Fitur baru telah tersedia di portal.</div>
Dengan Ikon
<div class="alert alert-info">
<span class="alert-icon">ℹ</span>
<span>Sesi Anda akan berakhir dalam 5 menit.</span>
</div>
Dengan Title
<div class="alert alert-warning">
<div class="alert-content">
<div class="alert-title">Perhatian</div>
Data yang dihapus tidak dapat dikembalikan.
</div>
</div>
Dengan Tombol Tutup
<div class="alert alert-info">
<div class="alert-content">
Pembaruan sistem dijadwalkan pada 20 Mei 2026.
</div>
<button class="alert-dismiss" onclick="this.closest('.alert').remove()">✕</button>
</div>
Ukuran
<div class="alert alert-info alert-sm">Alert ukuran kecil.</div>
<div class="alert alert-info">Alert ukuran default.</div>
<div class="alert alert-info alert-lg">Alert ukuran besar.</div>
Form Elements
Komponen form yang profesional, formal, dan minimalist dengan berbagai state dan variant.
Class Reference
| Class | Description |
|---|---|
| .form-input | Text input |
| .form-input-sm | Small input (36px) |
| .form-input-lg | Large input (52px) |
| .form-select | Select dropdown |
| .form-select-sm | Small select |
| .form-select-lg | Large select |
| .form-textarea | Textarea |
| .form-textarea-sm | Small textarea |
| .form-textarea-lg | Large textarea |
| .form-checkbox | Checkbox label wrapper |
| .form-checkbox-input | Checkbox input |
| .form-radio | Radio label wrapper |
| .form-radio-input | Radio input |
| .form-switch | Switch label wrapper |
| .form-switch-input | Switch input |
| .form-switch-sm | Small switch |
| .form-switch-lg | Large switch |
| .form-group | Form group wrapper |
| .form-group-error | Error state group |
| .form-group-success | Success state group |
| .form-label | Form label |
| .form-label-required | Required label marker |
| .form-hint | Hint text |
| .form-error | Error message |
| .input-wrap | Input with icon wrapper |
| .input-icon | Input icon |
| .input-group | Input with prefix/suffix |
| .input-group-text | Input group text |
Text Input
<div class="form-group">
<label class="form-label">Full Name</label>
<input type="text" class="form-input" placeholder="Enter your full name">
</div>
Input with Label Required
<label class="form-label form-label-required">Email Address</label>
Input Sizes
<input class="form-input form-input-sm">
<input class="form-input">
<input class="form-input form-input-lg">
Input with Hint
<div class="form-group">
<label class="form-label">Password</label>
<input type="password" class="form-input" placeholder="Enter password">
<span class="form-hint">Must be at least 8 characters</span>
</div>
Input with Error
<div class="form-group form-group-error">
<label class="form-label">Email</label>
<input type="email" class="form-input form-input-error" value="invalid-email">
<span class="form-error">Please enter a valid email address</span>
</div>
Input with Success
<div class="form-group form-group-success">
<label class="form-label">Username</label>
<input type="text" class="form-input" value="johndoe">
<span class="form-hint" style="color: var(--color-success);">Username is available</span>
</div>
Disabled Input
<input type="text" class="form-input" disabled>
<select class="form-select" disabled>...</select>
<textarea class="form-textarea" disabled>...</textarea>
Input with Icon
<div class="input-wrap">
<input type="text" class="form-input" placeholder="Search...">
<span class="input-icon">
<svg>...</svg>
</span>
</div>
<div class="input-wrap">
<input type="password" class="form-input">
<button class="input-action">...</button>
</div>
Input Group (Prefix/Suffix)
<div class="input-group">
<span class="input-group-text">https://</span>
<input type="text" class="form-input">
</div>
<div class="input-group">
<input type="text" class="form-input">
<span class="input-group-text">USD</span>
</div>
Select
<div class="form-group">
<label class="form-label">Country</label>
<select class="form-select">
<option value="">Select a country</option>
<option value="id">Indonesia</option>
</select>
</div>
Textarea
<textarea class="form-textarea" rows="4" placeholder="Enter your message..."></textarea>
Checkbox
<label class="form-checkbox">
<input type="checkbox" class="form-checkbox-input">
<span>I agree to the terms and conditions</span>
</label>
Checkbox Group
<div class="form-check-group">
<label class="form-checkbox">
<input type="checkbox" class="form-checkbox-input">
<span>Technology</span>
</label>
...
</div>
Radio
<div class="form-check-group">
<label class="form-radio">
<input type="radio" class="form-radio-input" name="payment">
<span>Credit Card</span>
</label>
...
</div>
Switch
<label class="form-switch">
<input type="checkbox" class="form-switch-input">
<span>Enable notifications</span>
</label>
<label class="form-switch form-switch-sm">...</label>
<label class="form-switch form-switch-lg">...</label>
Form Row (2 Columns)
<div class="form-row">
<div class="form-group">
<label class="form-label">First Name</label>
<input type="text" class="form-input">
</div>
<div class="form-group">
<label class="form-label">Last Name</label>
<input type="text" class="form-input">
</div>
</div>
Complete Form Example
JavaScript Components
import { CharCounter, PasswordToggle, SearchSelect, validateForm, setFieldError } from 'fondasi';
// Character counter for textarea
const counter = new CharCounter('#bio', { max: 200 });
// Password visibility toggle
const password = new PasswordToggle('#password-input');
// Searchable select (combobox)
const select = new SearchSelect('#country-select', {
options: [
{ value: 'id', label: 'Indonesia' },
{ value: 'sg', label: 'Singapore' }
]
});
// Form validation
const form = document.getElementById('my-form');
form.addEventListener('submit', (e) => {
if (!validateForm(form)) {
e.preventDefault();
}
});
// Set field error programmatically
setFieldError('#email-input', 'Invalid email format');
Search Select
Komponen input dengan fitur pencarian — tersedia dalam varian single-select dan multiple-select.
Class Reference
| Class / Atribut | Description |
|---|---|
| .search-select | Container single search select |
| .search-input | Input teks pencarian |
| .search-select-dropdown | Panel dropdown |
| .search-select-list | Daftar pilihan |
| .search-select-item | Item pilihan (data-value wajib) |
| .search-select-empty | Pesan empty state |
| .search-select-multi | Container multi search select |
| .search-select-tags | Area chips + input (multi) |
| .search-select-tag | Chip item terpilih (multi) |
| .search-select-tag-remove | Tombol hapus chip |
| data-name | Nama field untuk hidden input |
| data-placeholder | Placeholder teks input |
| data-no-data-text | Pesan ketika list kosong |
| data-empty-text | Pesan ketika hasil pencarian kosong |
| data-value (multi) | Nilai awal dipisah koma: "id,sg" |
Single Search Select
Pilih satu item dari daftar dengan fitur pencarian.
<div class="search-select">
<input type="hidden" name="country" value="">
<input type="text" class="search-input" placeholder="Search...">
<div class="search-select-dropdown" hidden>
<div class="search-select-list">
<div class="search-select-item" data-value="id">Indonesia</div>
<div class="search-select-item" data-value="sg">Singapore</div>
</div>
</div>
</div>
Empty State (No Data)
Ketika list kosong, dropdown tetap tampil dengan pesan yang dapat dikustomisasi.
<div class="search-select"
data-no-data-text="Tidak ada data tersedia."
data-empty-text="Tidak ada hasil yang cocok.">
<input type="hidden" name="field" value="">
<input type="text" class="search-input" placeholder="Search...">
<div class="search-select-dropdown" hidden>
<div class="search-select-list"></div>
</div>
</div>
Multiple Search Select
Pilih beberapa item sekaligus — setiap pilihan tampil sebagai chip yang bisa dihapus. Tekan Backspace untuk menghapus chip terakhir.
<div class="search-select-multi" data-name="languages">
<div class="search-select-item" data-value="js">JavaScript</div>
<div class="search-select-item" data-value="ts">TypeScript</div>
<div class="search-select-item" data-value="py">Python</div>
<div class="search-select-item" data-value="go">Go</div>
</div>
Multiple Select — Initial Values
Set nilai awal dengan data-value dipisah koma.
<div class="search-select-multi" data-name="roles" data-value="admin,editor">
<div class="search-select-item" data-value="admin">Admin</div>
<div class="search-select-item" data-value="editor">Editor</div>
<div class="search-select-item" data-value="viewer">Viewer</div>
</div>
JavaScript API
import { getSearchSelect, getMultiSearchSelect } from 'fondasi';
// Single select
const ss = getSearchSelect('#my-select', {
onSelect: ({ item }) => console.log('Selected:', item),
onClear: () => console.log('Cleared'),
});
ss.select('id'); // pilih by value
ss.clear(); // clear selection
ss.setItems([ // replace items
{ value: 'id', label: 'Indonesia' }
]);
// Multi select
const ms = getMultiSearchSelect('#my-multi', {
onSelect: ({ item }) => console.log('Added:', item),
onRemove: ({ item }) => console.log('Removed:', item),
});
ms.select('js'); // tambah by value
ms.deselect('js'); // hapus by value
ms.clear(); // hapus semua
console.log(ms.values); // ['ts', 'py']
Events
// Single select events
el.addEventListener('searchselect:select', e => console.log(e.detail.item));
el.addEventListener('searchselect:clear', () => {});
// Multi select events
el.addEventListener('multisearchselect:select', e => console.log(e.detail.item));
el.addEventListener('multisearchselect:remove', e => console.log(e.detail.item));
el.addEventListener('multisearchselect:clear', () => {});
Card
Komponen card untuk menampilkan konten dalam container.
Class Reference
| Class | Description |
|---|---|
| .card | Card container |
| .card-header | Card header |
| .card-body | Card body |
| .card-footer | Card footer |
Default Card
Card Title
This is the card body content. You can put any content here.
<div class="card">
<div class="card-header">
<h3>Card Title</h3>
</div>
<div class="card-body">
<p>This is the card body content.</p>
</div>
<div class="card-footer">
<button class="btn btn-primary">Action</button>
</div>
</div>
Card with Image
<div class="card">
<div class="card-image">
<img src="..." alt="...">
</div>
<div class="card-body">...</div>
</div>
Badge
Komponen badge untuk menampilkan label atau status.
Class Reference
| Class | Description |
|---|---|
| .badge | Default badge |
| .badge-success | Success variant |
| .badge-warning | Warning variant |
| .badge-danger | Danger variant |
| .badge-info | Info variant |
Variant: Default
<span class="badge">Default</span>
Variant: Success
<span class="badge badge-success">Success</span>
Variant: Warning
<span class="badge badge-warning">Warning</span>
Variant: Danger
<span class="badge badge-danger">Danger</span>
Variant: Info
<span class="badge badge-info">Info</span>
Badge in Table
| Status | Description |
|---|---|
| Active | Account is active |
| Pending | Awaiting approval |
| Inactive | Account disabled |
Table
Komponen table dua tingkat: CSS-only untuk tampilan statis, dan DataTable (JavaScript) untuk fitur interaktif — live search, sorting, seleksi baris, bulk actions, row expand, paginas bernomor, export CSV, dan skeleton loading.
CSS Class Reference
| Class | Keterangan |
|---|---|
| .table | Tabel dasar — full-width, border-collapse |
| .table-sm | Padding lebih kecil (compact) |
| .table-lg | Padding lebih besar |
| .table-striped | Baris genap diberi background alternatif |
| .table-bordered | Border di semua sisi setiap sel |
| .table-borderless | Hapus semua border bawah baris |
| .table-hover | Kursor pointer di setiap baris |
| .table-responsive | Stacked card layout di mobile (<768px) |
| .table-container | Wrapper overflow-x:auto untuk scroll horizontal |
| .table-wrap | Wrapper JS DataTable (border + rounded) |
| .table-toolbar | Bar di atas table (search, filter, actions) |
| .table-toolbar-left / -right | Section kiri / kanan dalam toolbar |
| .table-bulk-bar | Bar bulk actions — muncul saat ada baris dipilih |
| .table-bulk-count | Teks jumlah baris terpilih |
| .table-bulk-actions | Kumpulan tombol bulk action |
| .table-bulk-dismiss | Tombol batal pilih (X) di kanan bulk bar |
| .th-sortable | TH yang dapat diklik untuk sort (ditambah JS) |
| .th-sort-icon | Ikon ▲▼ di dalam TH yang sortable |
| .table-selectable | Ditambahkan ke <table> saat seleksi aktif |
| tr.selected | Baris yang sedang dipilih |
| .tr-expanded | Baris yang expandnya sedang terbuka |
| .tr-expand-row | Baris konten expand (disisipkan setelah baris utama) |
| .tr-expand-cell | TD di dalam baris expand |
| .tr-skeleton | Baris placeholder saat loading (shimmer animation) |
| .tr-empty | Baris empty state saat tidak ada data |
| .empty-icon | Ikon besar di empty state |
| .empty-title | Teks utama empty state |
| .empty-desc | Teks sekunder empty state (mis. hasil search) |
| .table-loading | Modifier pada table-wrap saat loading aktif |
| .table-footer | Bar bawah table (info + pagination) |
| .table-footer-info | Teks "Menampilkan X–Y dari Z" |
| .table-filter-badge | Badge "terfilter" muncul saat search aktif |
| .table-footer-pages | Kumpulan tombol nomor halaman |
| .table-page-ellipsis | Tanda … antar nomor halaman |
| .table-match | Highlight teks yang cocok dengan query search |
| .table-actions | Flex container untuk tombol aksi di setiap baris |
Data Attribute Reference
| Atribut | Pada Elemen | Keterangan |
|---|---|---|
| data-table | wrapper | Menandai container sebagai DataTable (deklaratif) |
| data-sortable="false" | wrapper | Nonaktifkan sorting (default: true) |
| data-selectable="true" | wrapper | Aktifkan seleksi baris |
| data-paginate="true" | wrapper | Aktifkan pagination client-side |
| data-page-size="10" | wrapper | Jumlah baris per halaman |
| data-search-input="id" | wrapper | ID dari <input> untuk live search |
| data-page-size-select-id="id" | wrapper | ID dari <select> untuk pilih jumlah baris |
| data-expandable="true" | wrapper | Aktifkan row expand |
| data-sort-col="nama" | wrapper | Kolom sort awal |
| data-sort-dir="asc|desc" | wrapper | Arah sort awal |
| data-empty-message="..." | wrapper | Teks empty state |
| data-col="key" | <th> | Kunci kolom untuk sorting |
| data-type="string|number|date" | <th> | Tipe data untuk algoritma sort |
| data-select-all | <input type="checkbox"> di thead | Checkbox select-all / deselect-all |
| data-row-check | <input type="checkbox"> di tbody | Checkbox per baris |
| data-value="..." | <td> | Nilai override untuk sort/export (jika isi TD berbeda) |
| data-search-text="..." | <td> | Teks override untuk filter search |
| data-expand-btn | <button> di baris | Tombol toggle expand baris |
| data-expand-content="html" | <tr> | Konten HTML yang ditampilkan saat expand |
| data-bulk-action="key" | <button> di bulk bar | Nama aksi yang dikirim ke callback onBulk |
| data-bulk-dismiss | <button> di bulk bar | Tombol untuk deselect semua baris |
| data-no-select | elemen dalam <tr> | Klik elemen ini tidak memicu seleksi baris |
Basic Table
| Nama | Peran | Status | |
|---|---|---|---|
| Andi Nugroho | andi@email.com | Admin | Aktif |
| Siti Rahayu | siti@email.com | Editor | Pending |
| Budi Prakoso | budi@email.com | Viewer | Nonaktif |
<table class="table">
<thead>
<tr>
<th>Nama</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Andi Nugroho</td>
<td><span class="badge badge-success">Aktif</span></td>
</tr>
</tbody>
</table>
Varian CSS
Striped
| ID | Produk | Harga |
|---|---|---|
| 001 | Produk A | Rp 100.000 |
| 002 | Produk B | Rp 200.000 |
| 003 | Produk C | Rp 150.000 |
Bordered
| ID | Produk | Harga |
|---|---|---|
| 001 | Produk A | Rp 100.000 |
| 002 | Produk B | Rp 200.000 |
Compact (table-sm)
| ID | Produk | Harga |
|---|---|---|
| 001 | Produk A | Rp 100.000 |
| 002 | Produk B | Rp 200.000 |
| 003 | Produk C | Rp 150.000 |
<table class="table table-striped">...</table>
<table class="table table-bordered">...</table>
<table class="table table-sm">...</table>
<table class="table table-lg">...</table>
<table class="table table-borderless">...</table>
DataTable — Demo Interaktif
Coba ketik di kolom pencarian, klik header untuk sort, pilih baris, atau klik ▶ untuk expand detail baris.
| Nama | Peran | Bergabung | Status | Detail | ||
|---|---|---|---|---|---|---|
| Andi Nugroho | andi@email.com | Admin | 12 Jan 2024 | Aktif | ||
| Siti Rahayu | siti@email.com | Editor | 8 Mar 2024 | Pending | ||
| Budi Prakoso | budi@email.com | Viewer | 24 Apr 2024 | Nonaktif | ||
| Dewi Lestari | dewi@email.com | Manager | 3 Jun 2024 | Aktif | ||
| Reza Firmansyah | reza@email.com | Editor | 17 Jul 2024 | Pending | ||
| Fitri Handayani | fitri@email.com | Viewer | 29 Agt 2024 | Aktif | ||
| Hendra Kurniawan | hendra@email.com | Admin | 5 Sep 2024 | Nonaktif | ||
| Maya Sari | maya@email.com | Manager | 11 Okt 2024 | Aktif |
Struktur HTML DataTable
<!-- 1. Search input (di luar wrapper, dihubungkan via ID) -->
<input type="text" id="mySearch" class="form-input form-input-sm" placeholder="Cari..." />
<!-- 2. Wrapper utama -->
<div id="myWrap" class="table-wrap"
data-table
data-selectable="true"
data-paginate="true"
data-page-size="10"
data-search-input="mySearch"
data-expandable="true">
<!-- 3. Bulk action bar (opsional) -->
<div class="table-bulk-bar" hidden>
<span class="table-bulk-count"></span>
<div class="table-bulk-actions">
<button data-bulk-action="export">Ekspor</button>
<button data-bulk-action="delete">Hapus</button>
</div>
<button data-bulk-dismiss>✕</button>
</div>
<div style="overflow-x:auto">
<table class="table">
<thead>
<tr>
<!-- 4. Checkbox select-all -->
<th><input type="checkbox" data-select-all /></th>
<!-- 5. TH sortable: data-col + data-type -->
<th data-col="nama">Nama</th>
<th data-col="tanggal" data-type="date">Tanggal</th>
</tr>
</thead>
<tbody>
<!-- 6. Baris dengan expand content -->
<tr data-expand-content="<p>Detail baris</p>">
<!-- 7. Checkbox per baris -->
<td><input type="checkbox" data-row-check /></td>
<td>Andi Nugroho</td>
<!-- 8. data-value untuk sort/export berbeda dari tampilan -->
<td data-value="2025-01-12">12 Jan 2025</td>
<td>
<!-- 9. Tombol expand -->
<button data-expand-btn aria-expanded="false">▶</button>
<!-- 10. Tombol lain: data-no-select agar tidak memicu seleksi -->
<button data-no-select>Hapus</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- .table-footer dirender otomatis oleh JS -->
</div>
JavaScript — Opsi Constructor
| Opsi | Tipe | Default | Keterangan |
|---|---|---|---|
| sortable | boolean | true | Aktifkan sort kolom (th[data-col]) |
| selectable | boolean | false | Aktifkan seleksi baris |
| multiSelect | boolean | true | Izinkan memilih lebih dari satu baris |
| paginate | boolean | false | Aktifkan pagination client-side |
| pageSize | number | 10 | Jumlah baris per halaman |
| expandable | boolean | false | Aktifkan row expand via data-expand-btn |
| searchInput | Element | string | — | Elemen atau ID <input> untuk live search |
| pageSizeSelect | Element | string | — | Elemen atau ID <select> pilih jumlah baris |
| sortCol | string | null | Kolom sort awal (nilai data-col) |
| sortDir | 'asc' | 'desc' | 'asc' | Arah sort awal |
| loading | boolean | false | Mulai dalam state loading |
| emptyMessage | string | 'Tidak ada data.' | Teks saat tidak ada baris |
| emptyIcon | string | '📭' | Ikon/emoji saat tidak ada baris |
| onSort | Function | null | Callback ({col, dir, table}) |
| onSelect | Function | null | Callback ({selected, row, table}) |
| onPage | Function | null | Callback ({page, pageSize, table}) |
| onSearch | Function | null | Callback ({query, table}) |
| onBulk | Function | null | Callback ({action, selected, table}) |
JavaScript — Methods
| Method | Parameter | Keterangan |
|---|---|---|
| search(query) | string | Filter baris secara programatik |
| sort(col, dir?) | string, 'asc'|'desc' | Sort berdasarkan kolom |
| selectRow(target) | Element | number | Pilih satu baris |
| deselectRow(target) | Element | number | Batalkan pilihan satu baris |
| selectAll() | — | Pilih semua baris yang tampil |
| deselectAll() | — | Batalkan semua pilihan |
| goTo(page) | number | Navigasi ke halaman tertentu (1-based) |
| next() | — | Halaman berikutnya |
| prev() | — | Halaman sebelumnya |
| exportCSV(filename?) | string | Download baris yang tampil sebagai CSV |
| setLoading(state, n?) | boolean, number | Tampilkan/sembunyikan skeleton (n = jumlah baris skeleton) |
| setRows(rows) | Element[] | string | Ganti semua data baris secara programatik |
JavaScript — Getters
| Getter | Tipe | Keterangan |
|---|---|---|
| .selectedRows | Element[] | Array baris yang sedang dipilih |
| .selectedCount | number | Jumlah baris yang dipilih |
| .currentPage | number | Nomor halaman aktif (1-based) |
| .totalPages | number | Total halaman berdasarkan filter aktif |
| .element | Element | Elemen container wrapper |
JavaScript — Custom Events
| Event | Detail | Keterangan |
|---|---|---|
| fondasi:table:sort | {col, dir, table} | Dipanggil setelah kolom diurutkan |
| fondasi:table:select | {selected, row, table} | Dipanggil saat baris dipilih/dibatalkan |
| fondasi:table:page | {page, pageSize, table} | Dipanggil saat halaman berpindah |
| fondasi:table:search | {query, table} | Dipanggil setelah search dijalankan |
| fondasi:table:bulk | {action, selected, table} | Dipanggil saat tombol bulk action diklik |
JavaScript — Inisialisasi
import { DataTable, getTable } from 'fondasi';
// ── Cara 1: Constructor langsung ─────────────────────────────
const table = new DataTable(document.getElementById('myWrap'), {
sortable: true,
selectable: true,
paginate: true,
pageSize: 10,
expandable: true,
searchInput: document.getElementById('mySearch'),
pageSizeSelect: document.getElementById('myPageSize'),
sortCol: 'nama',
sortDir: 'asc',
emptyMessage: 'Belum ada data tersedia.',
emptyIcon: '📭',
onBulk: ({ action, selected }) => {
if (action === 'export') table.exportCSV('data.csv');
if (action === 'delete') console.log('hapus', selected.length, 'baris');
},
onSearch: ({ query }) => console.log('search:', query),
onSelect: ({ selected }) => console.log(selected.length, 'dipilih'),
onPage: ({ page }) => console.log('halaman:', page),
});
// ── Cara 2: getTable (singleton per elemen) ──────────────────
const table = getTable('#myWrap', { sortable: true });
// ── Cara 3: Deklaratif via data-attribute ────────────────────
// Cukup tambahkan data-table + data-* pada wrapper di HTML
// lalu panggil Fondasi.initComponents() sekali saja
// ── Contoh penggunaan API ────────────────────────────────────
table.search('andi'); // filter langsung
table.sort('tanggal', 'desc'); // urutkan kolom
table.goTo(2); // ke halaman 2
table.selectAll(); // pilih semua baris tampil
table.exportCSV('laporan.csv'); // unduh CSV
table.setLoading(true, 5); // tampilkan 5 skeleton baris
// Dengarkan custom event
document.getElementById('myWrap').addEventListener('fondasi:table:select', e => {
console.log(e.detail.selected.length, 'baris dipilih');
});
Skeleton Loading
// Tampilkan skeleton saat fetch data
table.setLoading(true, 5); // 5 baris skeleton
// Setelah data selesai dimuat:
table.setRows(newRows); // isi data baru
// atau:
table.setLoading(false); // restore baris sebelumnya
Empty State
<!-- Ditambahkan otomatis oleh DataTable JS -->
<tr class="tr-empty">
<td colspan="N">
<span class="empty-icon">📭</span>
<div class="empty-title">Tidak ada data.</div>
<div class="empty-desc">Tidak ditemukan hasil untuk "<em>query</em>"</div>
</td>
</tr>
Tabs
Komponen tabs untuk navigasi konten bertingkat dengan berbagai variant.
Class Reference
| Class/Data Attribute | Description |
|---|---|
| .tabs | Container utama tabs |
| .tabs-list | Container untuk tab buttons |
| .tab | Tab button |
| .tab-active | State tab yang aktif |
| .tab-panel | Konten panel |
| .tabs-pills | Variant pills |
| .tabs-boxed | Variant boxed |
| .tabs-underline | Variant underline |
| .tabs-sm | Size small |
| .tabs-lg | Size large |
| .tabs-fit | Tab dengan lebar penuh |
| .tabs-centered | Tab rata tengah |
Default Tabs (Underline)
Dashboard content - Overview of your application metrics and key insights.
<div class="tabs">
<div class="tabs-list">
<button class="tab tab-active">Tab 1</button>
<button class="tab">Tab 2</button>
</div>
<div class="tab-panel tab-panel-show">Content 1</div>
</div>
Tabs: Pills
<div class="tabs tabs-pills">
<div class="tabs-list">
<button class="tab tab-active">Active</button>
<button class="tab">Inactive</button>
<button class="tab">Draft</button>
</div>
</div>
Tabs: Boxed
<div class="tabs tabs-boxed">
<div class="tabs-list">
<button class="tab tab-active">Overview</button>
<button class="tab">Details</button>
<button class="tab">History</button>
</div>
</div>
Tabs: Small
<div class="tabs tabs-sm">
<div class="tabs-list">
<button class="tab tab-active">Small</button>
<button class="tab">Tab</button>
</div>
</div>
Tabs: Large
<div class="tabs tabs-lg">
<div class="tabs-list">
<button class="tab tab-active">Large</button>
<button class="tab">Tab</button>
</div>
</div>
Tabs: Fit (Full Width)
<div class="tabs tabs-fit">
<div class="tabs-list">
<button class="tab tab-active">Tab 1</button>
<button class="tab">Tab 2</button>
<button class="tab">Tab 3</button>
<button class="tab">Tab 4</button>
</div>
</div>
JavaScript Usage
import { Tabs } from 'fondasi';
const tabs = new Tabs('[data-nusa-tabs]', {
activeClass: 'tab-active',
onChange: (tabId) => { console.log(tabId); }
});
Accordion
Komponen accordion untuk konten yang dapat dilipat.
Class Reference
| Class/Data Attribute | Description |
|---|---|
| data-nusa-accordion | Marks container as accordion |
| .accordion-item | Individual accordion item |
| .accordion-header | Clickable header toggle |
| .accordion-content | Collapsible content |
| data-accordion-toggle | Marks header as toggle |
Default Accordion
This is the content for the first accordion item. It can contain any HTML elements.
<div class="accordion" data-nusa-accordion>
<div class="accordion-item">
<button class="accordion-header" data-accordion-toggle>
<span>Item 1</span>
<span class="accordion-icon">+</span>
</button>
<div class="accordion-content">Content</div>
</div>
</div>
JavaScript Usage
import { Accordion } from 'fondasi';
const accordion = new Accordion('[data-nusa-accordion]', {
multiple: false,
animated: true
});
Modal
Komponen modal untuk dialog dan notifikasi penting.
Class Reference
| Class | Description |
|---|---|
| .modal-overlay | Modal container (wrapper) |
| .modal | Modal content box |
| .modal-header | Header section |
| .modal-body | Body content |
| .modal-footer | Footer with actions |
| data-modal-close | Closes modal on click |
| data-modal-open | Opens modal on click |
Default Modal
<!-- Trigger -->
<button data-modal-open="my-modal">Open Modal</button>
<!-- Modal -->
<div class="modal-overlay" id="my-modal" hidden>
<div class="modal">
<div class="modal-header">
<h3>Modal Title</h3>
<button data-modal-close>×</button>
</div>
<div class="modal-body">Content</div>
<div class="modal-footer">Footer</div>
</div>
</div>
Modal with Form
JavaScript Usage
import { Modal, getModal } from 'fondasi';
const modal = getModal('#my-modal');
modal.open();
modal.close();
// Or use Fondasi namespace (UMD)
Fondasi.Modal.open('#my-modal');
Fondasi.Modal.close('#my-modal');
Drawer
Komponen drawer untuk panel slide-in dari sisi.
Class Reference
| Class | Description |
|---|---|
| .drawer | Drawer container |
| .drawer-panel | Slide-in panel |
| .drawer-header | Header section |
| .drawer-body | Body content |
| data-drawer-close | Closes drawer on click |
| data-drawer-open | Opens drawer on click |
Drawer: Left
Left Drawer
This drawer slides in from the left side.
<!-- Trigger -->
<button data-drawer-open="my-drawer">Open Drawer</button>
<!-- Drawer -->
<div class="drawer" id="my-drawer">
<div class="drawer-backdrop"></div>
<div class="drawer-panel">
<div class="drawer-header">
<h3>Drawer Title</h3>
<button data-drawer-close>×</button>
</div>
<div class="drawer-body">Content</div>
</div>
</div>
Drawer: Right
Right Drawer
This drawer slides in from the right side.
JavaScript Usage
import { Drawer, getDrawer } from 'fondasi';
const drawer = getDrawer('#my-drawer');
drawer.open();
drawer.close();
Dropdown
Komponen dropdown untuk menu kontekstual dengan berbagai posisi, ukuran, dan varian item.
Class Reference
| Class / Atribut | Description |
|---|---|
| data-dropdown | Container utama dropdown |
| data-dropdown-toggle | Elemen yang membuka/menutup dropdown |
| .dropdown-menu | Panel menu |
| .dropdown-item | Item menu (link atau button) |
| .dropdown-item-disabled | Item non-interaktif |
| .dropdown-item-icon | Ikon di dalam item (14×14) |
| .dropdown-item-text | Label teks item (flex: 1) |
| .dropdown-item-shortcut | Keyboard shortcut hint |
| .dropdown-divider | Garis pemisah |
| .dropdown-label | Label group (uppercase, muted) |
| .dropdown-header | Header panel dropdown |
| .dropdown-end | Rata kanan (right-aligned) |
| .dropdown-top | Terbuka ke atas |
| .dropdown-center | Terpusat horizontal |
| .dropdown-sm | Menu lebih sempit (140px) |
| .dropdown-lg | Menu lebih lebar (200px) |
| .dropdown-open | State terbuka (ditambah JS) |
Default Dropdown
<div class="dropdown" data-dropdown>
<button class="btn btn-primary" data-dropdown-toggle>Dropdown</button>
<div class="dropdown-menu">
<a href="#" class="dropdown-item">Item 1</a>
<a href="#" class="dropdown-item">Item 2</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">Item 3</a>
</div>
</div>
Item dengan Icon, Label, dan Shortcut
<div class="dropdown" data-dropdown>
<button class="btn btn-outline" data-dropdown-toggle>Actions</button>
<div class="dropdown-menu">
<div class="dropdown-label">File</div>
<a href="#" class="dropdown-item">
<svg class="dropdown-item-icon" ...></svg>
<span class="dropdown-item-text">New File</span>
<span class="dropdown-item-shortcut">⌘N</span>
</a>
<div class="dropdown-divider"></div>
<!-- Item disabled -->
<button type="button" class="dropdown-item dropdown-item-disabled">
<span class="dropdown-item-text">Delete</span>
</button>
</div>
</div>
Posisi Menu
Kontrol arah buka menu dengan modifier class pada container.
<!-- Bottom start (default) -->
<div class="dropdown" data-dropdown>...</div>
<!-- Bottom end (rata kanan) -->
<div class="dropdown dropdown-end" data-dropdown>...</div>
<!-- Bottom center -->
<div class="dropdown dropdown-center" data-dropdown>...</div>
<!-- Terbuka ke atas -->
<div class="dropdown dropdown-top" data-dropdown>...</div>
Ukuran
<div class="dropdown dropdown-sm" data-dropdown>...</div> <!-- 140px -->
<div class="dropdown" data-dropdown>...</div> <!-- 180px default -->
<div class="dropdown dropdown-lg" data-dropdown>...</div> <!-- 200px -->
JavaScript API
import { Dropdown, getDropdown } from 'fondasi';
const dropdown = new Dropdown('[data-dropdown]', {
closeOnSelect: true,
closeOnOutside: true,
onOpen: () => {},
onClose: () => {},
onSelect: (item) => {},
});
// Get existing instance
const dd = getDropdown('#my-dropdown');
dd.open();
dd.close();
dd.toggle();
Topbar
Komponen header bar horizontal yang menampilkan aksi-aksi utama di bagian atas halaman. Biasanya digunakan bersama Sidebar untuk membangun layout aplikasi (app shell).
Class Reference
| Class | Description |
|---|---|
| .topbar | Container utama topbar (height 60px) |
| .topbar-left | Bagian kiri — flex, isi breadcrumb / mobile toggle |
| .topbar-center | Bagian tengah — rata tengah |
| .topbar-right | Bagian kanan — flex, isi icon buttons |
| .topbar-title | Judul halaman dalam topbar |
| .topbar-btn | Tombol ikon 36×36px di dalam topbar |
| .topbar-badge | Dot notifikasi di sudut tombar-btn |
| .topbar-badge-count | Badge angka notifikasi di sudut topbar-btn |
| .topbar-divider | Pemisah vertikal antar section |
| .topbar-sticky | Modifier: sticky ke atas layar |
| .topbar-elevated | Modifier: shadow, tanpa border bawah |
| .topbar-dark | Modifier: latar belakang gelap (brand-darker) |
Default Topbar
<header class="topbar topbar-sticky">
<div class="topbar-left">
<span class="topbar-title">Dashboard</span>
</div>
<div class="topbar-right">
<button class="topbar-btn">...</button>
</div>
</header>
Topbar dengan Badge Notifikasi
<button class="topbar-btn">
<!-- icon SVG -->
<span class="topbar-badge"></span> <!-- dot merah -->
<span class="topbar-badge-count">3</span> <!-- angka -->
</button>
<div class="topbar-divider"></div>
Topbar Dark
<header class="topbar topbar-sticky topbar-dark">
...
</header>
Toast
Notifikasi popup yang muncul dari pojok layar. Formal, minimalist, dan menarik.
Interactive Demo
Klik tombol di bawah untuk menampilkan toast di pojok kanan bawah:
Toast with Actions
Class Reference
| Class | Description |
|---|---|
| .toast-container | Container untuk toast |
| .toast | Toast element |
| .toast-success | Success variant |
| .toast-warning | Warning variant |
| .toast-danger | Error/Danger variant |
| .toast-info | Info variant |
| .toast-icon-wrapper | Icon container dengan background |
| .toast-content | Content wrapper |
| .toast-title | Judul toast |
| .toast-message | Pesan detail |
| .toast-actions | Container untuk action buttons |
| .toast-progress | Progress bar untuk durasi |
HTML Structure
<div class="toast toast-success">
<div class="toast-icon-wrapper">
<svg class="toast-icon">...</svg>
</div>
<div class="toast-content">
<div class="toast-title">Success!</div>
<div class="toast-message">Your changes have been saved.</div>
</div>
<button class="toast-close">...</button>
</div>
JavaScript Usage
import { getToast } from 'fondasi';
const toast = getToast();
// Basic toast
toast.show('Message text', 'success');
// With title
toast.show('Operation completed', 'success', {
title: 'Success'
});
// With actions
toast.show('File uploaded successfully', 'success', {
actions: [
{ label: 'View', onClick: () => console.log('view') },
{ label: 'Undo', onClick: () => console.log('undo') }
]
});
// Auto dismiss with duration
toast.show('Message', 'info', { duration: 5000 });
Avatar
Komponen avatar untuk menampilkan representasi pengguna dengan berbagai ukuran, bentuk, dan status.
Class Reference
| Class | Description |
|---|---|
| .avatar | Default avatar |
| .avatar-sm | Small size (24px) |
| .avatar-md | Medium size (32px) |
| .avatar-lg | Large size (40px) |
| .avatar-xl | Extra large (56px) |
| .avatar-square | Square shape |
| .avatar-circle | Circle shape |
| .avatar-rounded | Rounded corners |
| .avatar-status | Avatar with status indicator |
| .avatar-status-online | Online status |
| .avatar-status-offline | Offline status |
| .avatar-status-busy | Busy status |
| .avatar-status-away | Away status |
| .avatar-brand | Brand color variant |
| .avatar-success | Success color variant |
| .avatar-warning | Warning color variant |
| .avatar-danger | Danger color variant |
| .avatar-info | Info color variant |
| .avatar-group | Avatar group container |
| .avatar-group-sm | Small group |
| .avatar-group-lg | Large group |
| .avatar-group-xl | Extra large group |
| .avatar-initial | Text initial display |
Sizes
<div class="avatar avatar-sm" data-initial="SM"></div>
<div class="avatar avatar-md" data-initial="MD"></div>
<div class="avatar avatar-lg" data-initial="LG"></div>
<div class="avatar avatar-xl" data-initial="XL"></div>
Shapes
<div class="avatar avatar-md" data-initial="SQ"></div>
<div class="avatar avatar-md avatar-circle" data-initial="CI"></div>
<div class="avatar avatar-md avatar-rounded" data-initial="RD"></div>
With Image Source
<div class="avatar avatar-md avatar-circle" data-src="https://i.pravatar.cc/150?img=68"></div>
With Initials
<div class="avatar avatar-md" data-initial="JD"></div>
<div class="avatar avatar-md avatar-circle" data-initial="AB"></div>
<div class="avatar avatar-md avatar-rounded" data-initial="XY"></div>
Status Indicator
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-online" data-initial="ON"></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-offline" data-initial="OF"></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-busy" data-initial="BS"></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-away" data-initial="AW"></div>
Color Variants
<div class="avatar avatar-md" data-initial="B"></div>
<div class="avatar avatar-md avatar-circle" data-initial="S"></div>
<div class="avatar avatar-md avatar-brand" data-initial="B"></div>
<div class="avatar avatar-md avatar-circle avatar-brand" data-initial="B"></div>
<div class="avatar avatar-md avatar-success" data-initial="S"></div>
<div class="avatar avatar-md avatar-warning" data-initial="W"></div>
<div class="avatar avatar-md avatar-danger" data-initial="D"></div>
<div class="avatar avatar-md avatar-info" data-initial="I"></div>
Fallback: Icon (No image, no initial)
<div class="avatar avatar-sm"></div>
<div class="avatar avatar-md"></div>
<div class="avatar avatar-lg"></div>
<div class="avatar avatar-md avatar-circle"></div>
<div class="avatar avatar-md avatar-rounded"></div>
Avatar Group (Stack)
<div class="avatar-group">
<div class="avatar avatar-md avatar-circle" data-initial="JD"></div>
<div class="avatar avatar-md avatar-circle" data-initial="AB"></div>
<div class="avatar avatar-md avatar-circle" data-initial="CD"></div>
<div class="avatar avatar-md avatar-circle" data-initial="EF"></div>
</div>
Avatar Group with Overflow
<div class="avatar-group" data-max="3">
<div class="avatar avatar-md avatar-circle" data-initial="A"></div>
<div class="avatar avatar-md avatar-circle" data-initial="B"></div>
<div class="avatar avatar-md avatar-circle" data-initial="C"></div>
<div class="avatar avatar-md avatar-circle" data-initial="D"></div>
<div class="avatar avatar-md avatar-circle" data-initial="E"></div>
<div class="avatar avatar-md avatar-circle" data-initial="F"></div>
</div>
Avatar Group Sizes
<div class="avatar-group avatar-group-sm">...</div>
<div class="avatar-group avatar-group-md">...</div>
<div class="avatar-group avatar-group-lg">...</div>
<div class="avatar-group avatar-group-xl">...</div>
Avatar with Images and Status
<div class="avatar-group">
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-online" data-src="..."></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-offline" data-src="..."></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-busy" data-initial="JD"></div>
<div class="avatar avatar-md avatar-circle avatar-status avatar-status-away" data-initial="AB"></div>
</div>
JavaScript API
Create Avatar Programmatically
import { createAvatar, createAvatarGroup } from 'fondasi';
// Create single avatar
const avatar = createAvatar({
src: 'https://example.com/photo.jpg',
initial: 'JD',
size: 'md',
shape: 'circle',
status: 'online',
variant: 'brand'
});
// Create avatar group
const group = createAvatarGroup([
{ initial: 'JD', status: 'online' },
{ initial: 'AB', status: 'offline' },
{ src: 'https://example.com/photo.jpg' }
], { size: 'md', max: 3 });
Events
| Event | Description |
|---|---|
| avatar:load | Fired when image loads successfully |
| avatar:error | Fired when image fails to load |
document.querySelector('.avatar').addEventListener('avatar:load', (e) => {
console.log('Image loaded:', e.detail.src);
});
document.querySelector('.avatar').addEventListener('avatar:error', (e) => {
console.log('Image failed:', e.detail.src);
});
Layout System
Sistem layout dasar menggunakan container dan spacing.
Container
<div class="container">
<!-- content -->
</div>
Width
| Class | Description |
|---|---|
| .w-full | width: 100% |
| .w-auto | width: auto |
| .w-screen | width: 100vw |
| .w-min | width: min-content |
| .w-max | width: max-content |
Height
| Class | Description |
|---|---|
| .h-full | height: 100% |
| .h-auto | height: auto |
| .h-screen | height: 100vh |
| .h-min | height: min-content |
| .h-max | height: max-content |
Flex
Utility classes untuk flexbox layout.
Display
<div class="flex">...</div>
<div class="inline-flex">...</div>
Flex Direction
| Class | CSS |
|---|---|
| .flex-row | flex-direction: row |
| .flex-row-reverse | flex-direction: row-reverse |
| .flex-col | flex-direction: column |
| .flex-col-reverse | flex-direction: column-reverse |
Justify Content
| Class | CSS |
|---|---|
| .justify-start | justify-content: flex-start |
| .justify-end | justify-content: flex-end |
| .justify-center | justify-content: center |
| .justify-between | justify-content: space-between |
| .justify-around | justify-content: space-around |
Align Items
| Class | CSS |
|---|---|
| .items-start | align-items: flex-start |
| .items-end | align-items: flex-end |
| .items-center | align-items: center |
| .items-stretch | align-items: stretch |
Gap
<div class="flex gap-2">...</div>
<div class="flex gap-4 gap-6-md">...</div>
Grid
Utility classes untuk CSS Grid layout.
Grid Columns
<div class="grid grid-cols-2">...</div>
<div class="grid grid-cols-3">...</div>
<div class="grid grid-cols-4">...</div>
| Class | Columns |
|---|---|
| .grid-cols-1 | 1 column |
| .grid-cols-2 | 2 columns |
| .grid-cols-3 | 3 columns |
| .grid-cols-4 | 4 columns |
| .grid-cols-6 | 6 columns |
| .grid-cols-12 | 12 columns |
Grid Span
<div class="grid-col-span-2">...</div>
<div class="grid-col-span-3">...</div>
Utility Classes
Kumpulan utility classes yang tersedia.
Display
| Class | CSS |
|---|---|
| .block | display: block |
| .inline-block | display: inline-block |
| .inline | display: inline |
| .hidden | display: none |
Position
| Class | CSS |
|---|---|
| .relative | position: relative |
| .absolute | position: absolute |
| .fixed | position: fixed |
| .sticky | position: sticky |
Border Radius
| Class | CSS |
|---|---|
| .rounded-none | border-radius: 0 |
| .rounded | border-radius: var(--radius-md) |
| .rounded-lg | border-radius: var(--radius-lg) |
| .rounded-full | border-radius: 9999px |
Shadow
| Class | Description |
|---|---|
| .shadow-none | No shadow |
| .shadow-sm | Small shadow |
| .shadow | Default shadow |
| .shadow-lg | Large shadow |
Transitions
| Class | CSS |
|---|---|
| .transition-none | transition: none |
| .transition-all | transition: all var(--transition-base) |
| .transition-colors | transition for colors |
| .transition-opacity | transition for opacity |
| .transition-transform | transition for transform |
Sizing
Utility classes untuk mengatur width dan height.
Width
<div class="w-1/2">50%</div>
<div class="w-1/3">33.33%</div>
<div class="w-3/4">75%</div>
<div class="w-auto">auto</div>
Height
<div class="h-screen">100vh</div>
<div class="h-auto">auto</div>
<div class="h-full">100%</div>
Min/Max
<div class="min-h-screen">min-height: 100vh</div>
<div class="max-w-md">max-width: 28rem</div>
<div class="max-w-lg">max-width: 32rem</div>
Interaction
Utility classes untuk interaksi pengguna.
Cursor
| Class | CSS |
|---|---|
| .cursor-pointer | cursor: pointer |
| .cursor-default | cursor: default |
| .cursor-not-allowed | cursor: not-allowed |
| .cursor-move | cursor: move |
User Select
| Class | CSS |
|---|---|
| .select-none | user-select: none |
| .select-text | user-select: text |
| .select-all | user-select: all |
Pointer Events
| Class | CSS |
|---|---|
| .pointer-events-none | pointer-events: none |
| .pointer-events-auto | pointer-events: auto |
JavaScript API
Referensi lengkap API JavaScript Fondasi.
Inisialisasi
// ES Modules
import { initComponents } from 'fondasi';
initComponents(); // Initialize all components
// UMD / Browser
Fondasi.initComponents();
Available Exports
| Export | Description |
|---|---|
| initComponents | Inisialisasi semua komponen |
| Modal | Modal component (open/close) |
| Drawer | Drawer component (open/close) |
| Tabs | Tabs component |
| Accordion | Accordion component |
| Dropdown | Dropdown component |
| Sidebar | Sidebar component |
| DataTable | Table component |
| getToast | Toast manager |
| theme | Theme manager (light/dark) |
| CharCounter | Character counter |
| PasswordToggle | Password visibility toggle |
| SearchSelect | Searchable select |
| FormValidation | Form validation |
Theme
import { theme } from 'fondasi';
// Toggle dark mode
theme.toggle();
// Set specific mode
theme.setMode('dark');
theme.setMode('light');
// Check current mode
theme.getMode(); // 'light' or 'dark'
Template — Dashboard
Template siap pakai untuk membangun halaman dashboard dalam portal SIMPATTI. Setiap aplikasi portal cukup menyalin template ini dan melakukan konfigurasi minimal di APP_CONFIG.
Gambaran Umum
Template Dashboard dirancang untuk portal multi-aplikasi di mana setiap aplikasi memiliki:
- Layout yang seragam — Sidebar + Topbar + Main Content
- Warna/tema yang berbeda per aplikasi, cukup set satu warna dasar
- Menu sidebar dan fitur yang dapat dikustomisasi sepenuhnya
Struktur File Aplikasi
Setiap aplikasi dalam portal memiliki foldernya sendiri dengan tiga file utama:
portal/
├── shared/
│ ├── fondasi.css ← dari CDN atau shared lib
│ └── fondasi.js
│
└── apps/
├── akademik/
│ ├── index.html ← salin dari template dashboard
│ ├── app.css ← override/tambahan CSS khusus app
│ └── app.js ← logika bisnis khusus app
│
├── keuangan/
│ ├── index.html
│ ├── app.css
│ └── app.js
│
└── [nama-app]/
├── index.html
├── app.css
└── app.js
Quick Start
Langkah membuat aplikasi baru dari template ini:
- Unduh dan salin folder
src/templates/dashboard/ke direktori aplikasi baru - Ganti URL Fondasi (CSS & JS) dengan CDN URL yang sesuai di
index.html - Edit
APP_CONFIGdi bagian atasapp.js - Sesuaikan menu sidebar di
index.htmldan tambahkan logika bisnis diapp.js
APP_CONFIG
Satu-satunya titik konfigurasi wajib per aplikasi. Letakkan di bagian atas blok <script>.
// Nilai default dalam template (app.js)
const APP_CONFIG = {
name: 'Dashboard', // Ganti dengan nama aplikasi
baseColor: '#1e3a5f', // Ganti dengan warna dasar brand aplikasi
user: {
name: '[Nama Pengguna]', // Isi dari session / auth
role: '[Peran / Jabatan]',
initials: 'AD', // 2 huruf untuk avatar
},
};
// Contoh setelah dikustomisasi untuk aplikasi Akademik:
// const APP_CONFIG = {
// name: 'Akademik',
// baseColor: '#1e6b3f',
// user: { name: 'Andi Nugroho', role: 'Administrator', initials: 'AN' },
// };
| Key | Tipe | Keterangan |
|---|---|---|
| name | string | Nama aplikasi. Muncul di <title> dan brand sidebar. |
| baseColor | hex string | Warna dasar brand. Diproses oleh setAppTheme() untuk generate semua token warna. |
| user.name | string | Nama pengguna aktif — isi dari session/auth aplikasi. |
| user.role | string | Peran atau jabatan pengguna. |
| user.initials | string | Dua huruf untuk avatar (misalnya "AN" dari "Andi Nugroho"). |
setAppTheme(baseColor)
Fungsi ini menerima satu warna hex dan secara otomatis menghasilkan seluruh skala warna brand. Token yang di-generate langsung menggantikan variabel CSS Fondasi, sehingga semua komponen (button, form, tabs, checkbox, sidebar, dll.) ikut menyesuaikan warna secara otomatis.
// Contoh penggunaan langsung
setAppTheme('#1e6b3f'); // Hijau — untuk app Akademik
setAppTheme('#7c3aed'); // Ungu — untuk app Kurikulum
setAppTheme('#b45309'); // Amber — untuk app Keuangan
Token CSS yang di-generate:
| Token | Keterangan |
|---|---|
| --color-brand | Warna dasar (input langsung) |
| --color-brand-default | Sama dengan base — token utama yang dipakai seluruh komponen Fondasi |
| --color-brand-dark | 10% lebih gelap — hover state button & link |
| --color-brand-darker | 20% lebih gelap — active/pressed state |
| --color-brand-light | Versi sangat terang — background highlight & focus ring |
| --color-brand-mid | Versi medium — border & divider bernuansa brand |
| --color-brand-accent | Sedikit lebih cerah — CTA dan fokus |
| --color-brand-rgb | Nilai RGB untuk dipakai di rgba() |
Layout Struktur
Template menggunakan pola Sidebar Fixed + Topbar Sticky + Main Content.
<body>
<!-- Overlay mobile (tampil saat sidebar terbuka di mobile) -->
<div class="sidebar-overlay" id="sidebarOverlay"></div>
<!-- Sidebar (fixed kiri, light mode) -->
<aside class="sidebar" id="mainSidebar">
<div class="sidebar-header">...</div> <!-- Logo + toggle -->
<div class="sidebar-content">...</div> <!-- Nav sections -->
<div class="sidebar-footer">...</div> <!-- Avatar + Profil + Keluar -->
</aside>
<!-- Wrapper utama (margin-left mengikuti lebar sidebar) -->
<div class="app-wrapper" id="appWrapper">
<!-- Topbar (sticky top) -->
<header class="topbar">
<div class="topbar-left">...</div> <!-- Mobile toggle + Breadcrumb -->
<div class="topbar-right">...</div> <!-- Notifikasi, user -->
</header>
<!-- Konten halaman -->
<main class="main-content">
...
</main>
</div>
<!-- Modal, Drawer di sini -->
</body>
CSS Layout Classes
Kelas-kelas berikut adalah bagian dari app shell yang harus didefinisikan di app.css atau di blok <style> dalam template (bukan bagian dari Fondasi):
| Class | Keterangan |
|---|---|
| .app-wrapper | Wrapper utama. margin-left: 260px mengikuti lebar sidebar. |
| .app-wrapper.sidebar-is-collapsed | Diterapkan oleh JS saat sidebar collapsed. Ubah margin menjadi 68px. |
| .topbar | Header sticky dengan tinggi 60px. |
| .main-content | Area konten utama dengan padding var(--space-6). |
Komponen Fondasi yang Dipakai
| Komponen | Letak dalam Template |
|---|---|
| Sidebar | Navigasi utama aplikasi (kiri, light mode) |
| Dropdown | Menu notifikasi dan menu user (dengan data-placement="bottom-end") |
| Breadcrumb | Navigasi hierarki di topbar |
| Card | Stat cards & container konten utama |
| Tabs | Segmentasi data (Semua / Aktif / Arsip) |
| Table | Tampilan data dengan aksi per baris |
| Badge | Indikator status (Aktif, Pending, Nonaktif) |
| Button | Aksi primer, outline, ghost, dan danger |
| Form | Input, select, textarea, checkbox di filter & modal |
| Modal | Detail data & form tambah/edit |
| Drawer | Panel filter dari kanan layar |
| Toast | Feedback aksi (sukses, error, info, warning) |
| Avatar | Inisial pengguna di sidebar footer & topbar |
Inisialisasi JavaScript
Template menginisialisasi semua komponen Fondasi melalui UMD global Fondasi yang tersedia setelah fondasi.js dimuat.
// app.js — inisialisasi komponen di DOMContentLoaded
document.addEventListener('DOMContentLoaded', function () {
// 1. Terapkan tema warna aplikasi
setAppTheme(APP_CONFIG.baseColor);
// 2. Sidebar — sinkronkan margin wrapper saat collapse/expand
const sidebar = new Fondasi.Sidebar(document.getElementById('mainSidebar'), {
onChange: ({ isCollapsed }) => {
document.getElementById('appWrapper')
.classList.toggle('sidebar-is-collapsed', isCollapsed);
},
});
// 3. Tabs
const tabs = new Fondasi.Tabs(document.getElementById('mainTabs'));
// 4. Drawer (filter) dan Modal (detail + form)
const filterDrawer = new Fondasi.Drawer(document.getElementById('filterDrawer'));
const detailModal = new Fondasi.Modal(document.getElementById('detailModal'));
const formModal = new Fondasi.Modal(document.getElementById('formModal'));
// 5. Toast
const toast = new Fondasi.ToastManager({ position: 'top-right' });
// 6. Semua dropdown (notifikasi, user)
document.querySelectorAll('.dropdown').forEach(el => new Fondasi.Dropdown(el));
// 7. Mobile sidebar toggle
const mobileSidebarBtn = document.getElementById('mobileSidebarToggle');
const sidebarOverlay = document.getElementById('sidebarOverlay');
if (mobileSidebarBtn) {
mobileSidebarBtn.addEventListener('click', () => {
document.getElementById('mainSidebar').classList.toggle('sidebar-open');
sidebarOverlay.classList.toggle('sidebar-overlay-open');
});
}
});
Kustomisasi Sidebar
Ganti placeholder menu di dalam .sidebar-content sesuai fitur aplikasi. Template menyediakan tiga section: Utama, Manajemen, dan Sistem.
<!-- Tambah menu baru -->
<a href="halaman.html" class="sidebar-link">
<svg class="sidebar-nav-icon" ...>...</svg>
<span class="sidebar-nav-text">Nama Menu</span>
<span class="sidebar-nav-badge">3</span> <!-- opsional -->
</a>
<!-- Tandai menu aktif -->
<a href="halaman.html" class="sidebar-link active">...</a>
CDN URL
Template menggunakan path lokal (../../../dist/) untuk pengembangan dari lokasi src/templates/dashboard/. Ganti dengan CDN URL sebelum deploy:
<!-- Development (lokal) — dari src/templates/dashboard/ -->
<link rel="stylesheet" href="../../../dist/fondasi.css">
<script src="../../../dist/fondasi.js"></script>
<!-- Production (CDN) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/bideyesa/fondasi@latest/dist/fondasi.min.css">
<script src="https://cdn.jsdelivr.net/gh/bideyesa/fondasi@latest/dist/fondasi.min.js"></script>