Lewati ke konten utama

Komponen

Design System · v3.17.0

Konsisten dari token sampai layar bisnis.

Freeday adalah sumber kebenaran token-driven & framework-agnostic. Warna, tipografi, spasi, dan 45 komponen aksesibel yang dirakit jadi layar nyata di Vue, React, atau Blazor. Nol dependency runtime, kontras WCAG AA di terang & gelap.

Referensi lengkap: COMPONENTS.md (semua class + markup) · USAGE.md (kapan pakai yang mana) · satu layar utuh · panduan AI agent.

$ npm i @cahyo-dimas/freeday
45komponen
22enhancer · 0-dep
3adapter framework
AAkontras · terang & gelap

Integrasi framework

Adapter tipis: enhancer tetap sumber kebenaran, event fdy-* dijembatani ke reaktivitas framework. Vue, React, dan Blazor kini sama-sama punya komponen typed (10/10 parity): FdyCombo, FdyDatepicker, FdyCfl, FdyChart, FdyTable, FdyModal/FdyDrawer, dst. Tiap stack punya contoh layar faktur yang jalan (lihat examples/).

Baru mau pakai di project sendiri? Panduan langkah-demi-langkah per stack →

Playground

Pilih komponen, atur varian lewat kontrol Freeday (chip & switch), lihat pratinjau langsung, lalu salin markup-nya. Semua kelas berasal dari kit, nol dependency, siap tempel ke Vue / React / Blazor.

Komponen
HTML

Prinsip

Empat aturan yang menjaga sistem tetap konsisten seiring pertumbuhannya.

1 · Semantic saja

Komponen hanya menyentuh peran (Tier-2), tak pernah ramp mentah. Re-brand & tema cukup ubah token semantic.

2 · Grid 4px

Semua spasi kelipatan 4px lewat skala --space-*. Tak pernah nilai lepas.

3 · Satu aksen per layar

Satu aksi primer menonjol; sisanya ghost/secondary. Warna status ≠ warna aksen.

4 · Aksesibel sejak awal

Kontras WCAG AA di terang & gelap, fokus selalu terlihat, HTML native dulu sebelum ARIA.

Warna

Peran semantic (Tier-2). Komponen hanya menyentuh peran ini, tak pernah ramp mentah.

Palet primary: data-primary. 18 pilihan. Yang di-redefinisi adalah ramp alias delapan shade, bukan token semantic-nya — jadi pemetaan "shade mana yang jadi fill, hover, wash" ditulis sekali dan sebuah palet tak mungkin berbeda pendapat soal arti "primary". Bisa dipasang di <html> atau di wrapper mana pun untuk me-rebrand satu region. Setiap palet dijaga gerbang kontras di kedua tema; tiga hasilnya tampak seperti kekeliruan kalau tak dijelaskan: yellow memakai fill lebih gelap di tema terang (di shade aslinya cuma 2.94:1 di atas putih) dan karenanya berlabel putih, sedangkan indigo dan violet bergeser satu langkah lebih terang di tema gelap. noir bukan hue sama sekali — ia mengarahkan ramp alias ke ramp netral.

Tekan salah satu, lalu telusuri halaman ini: tombol, tab, fokus, chart, dan setiap -soft wash ikut berubah tanpa satu baris pun disetel per komponen.

Gaya visual: data-style. soft default; glass memfrost permukaan terangkat saja — card, modal, drawer, menu, appbar, sidebar & topbar app shell. Sengaja bukan --color-surface, karena token itu juga jadi isian input, chip, sel tabel dan kolom beku; kolom beku yang tembus pandang akan memperlihatkan baris yang menggulung di bawahnya. Seberapa tembus kaca boleh jadi ditentukan gerbang kontras, bukan selera: di bawah .82 (terang) / .90 (gelap), tinta muted berhenti lolos 4.5:1 begitu panel dikomposit di atas latar sembarang. Jadi frost-nya halus — yang benar-benar terlihat adalah blur-nya, bukan alpha-nya.

Tipografi

Display Sora · body IBM Plex Sans · data JetBrains Mono.

Faktur & laporan yang rapi

Teks isi memakai IBM Plex Sans, nyaman dibaca untuk paragraf, label, dan tabel data bisnis sehari-hari.

INV-1042 · Rp 1.240.000 · 2026-07-30

Spasi

Skala kelipatan 4px. Selalu var(--space-N), tak pernah nilai lepas.

--space-1 ·
--space-2 ·
--space-3 ·
--space-4 ·
--space-5 ·
--space-6 ·
--space-8 ·
--space-10 ·
--space-12 ·
--space-16 ·

Radius & Elevasi

Sudut & bayangan bertingkat, untuk hierarki kedalaman yang konsisten.

Radius

xs ·
sm ·
md ·
lg ·
xl ·
full

Elevasi

shadow-1
shadow-2
shadow-3
shadow-4

Motion

Skala gerak terbatas & konsisten: tiga durasi (--dur-fast · --dur-base · --dur-slow ) dan dua easing yang keduanya decelerate (tanpa bounce/elastic). Gerak hanya untuk feedback, reveal, dan transisi state, bukan dekorasi. Semua otomatis nonaktif saat prefers-reduced-motion: reduce. Arahkan kursor ke track untuk merasakan easing-nya.

base · · ease-standard
slow · · ease-spring

Yang bergerak: Drawer & Modal beranimasi masuk dan keluar (slide / fade-scale + backdrop blur) lewat @starting-style + allow-discrete pada <dialog> native: buka lalu tutup, perhatikan animasi keluarnya. Overlay (menu, select, cascade, autocomplete, date/time picker) reveal saat dibuka; Accordion & Tabs me-reveal konten (fade + rise); baris tabel & kontrol punya transisi hover/press halus.

Tombol

Gradient gelap-ke-bawah + colored-glow. Satu aksi primer per layar; sisanya ghost.

Text + ikon · text-only (emphasis rendah) · icon-only (butuh aria-label).

Button group (segmented, mendatar atau --stack bertumpuk untuk memilih satu dengan ibu jari) & FAB (bulat · kecil · extended).

Menu & Split button

Popup aksi (pola menu-button WAI-ARIA APG) dengan keyboard ↑/↓/Home/End/Esc. Split button = aksi utama + toggle menu. Butuh freeday-menu.js.

Input

Inner-shadow + focus glow. Untuk error, pakai aria-invalid="true". Atribut ini melakukan dua hal sekaligus (state visual dan yang bisa dibaca screen reader), lalu aria-describedby menautkan pesan (help ber-id sama). .fdy-input--error hanya untuk kasus di mana state invalid bukan milik field itu sendiri.

Hari kerja

Input group

Addon prefix/suffix bebas: teks (Rp / %), ikon dekoratif (__addon--icon), tombol aksi (__btn), atau tanpa addon sama sekali. Jadi "dengan ikon / tanpa ikon / ikon custom" cukup dari markup addon. Field angka = grup yang sama dengan dua tombol step, yaitu data-fdy-number.

Rp
%

Choose-from-list

Field read-only yang di-backing master data (pelanggan, item, gudang…). Ikon kaca pembesar di kanan membuka dialog pencari; baris yang dipilih mengisi field (kode + nama sekaligus). Nilai selalu dipilih, tak pernah diketik. Multi-pilih: data-fdy-cfl-multiple pada dialog untuk jalur enhancer, atau prop multiple pada wrapper Vue/React (model melebar jadi Row[] | null) dan Multiple + Values pada Blazor. Baris dicentang, footer menghitung, dan Confirm yang meng-commit. Menutup dialog tanpa Confirm tak mengubah nilai sama sekali. Butuh freeday-cfl.js.

Kode pelanggan
Nilai dipilih, bukan diketik.
Terisi otomatis dari baris terpilih.
Centang beberapa baris, lalu konfirmasi.

Pilih pelanggan

KodeNamaKotaSaldo
C-1001PT Sumber MakmurJakarta12.400.000
C-1002CV Berkah JayaBandung3.150.000
C-1003UD Cahaya AbadiSurabaya780.000
C-1004PT Mitra SentosaSemarang0
C-1005Toko Rejeki MakmurMedan5.600.000

Pilih item

PilihKodeNamaHarga
ITM-01Kertas A4 80gsm52.000
ITM-02Tinta Printer Hitam185.000
ITM-03Map Snelhecter3.500
ITM-04Pulpen Gel 0.512.000

Single-select commit saat klik baris (tanpa "OK"). Keyboard: ketik untuk mencari, ↓ masuk daftar, ↑/↓ navigasi, Enter pilih, Esc tutup. Fokus kembali ke tombol pemicu saat ditutup. Baris = server state: di app nyata, jadikan komponen terkontrol (callback fetchPage + cache), bukan store global.

Date picker

Trigger bergaya input + kalender popover, konsisten lintas-browser & bisa di-theme. (Native <input type="date"> tetap pilihan ringan bila tak butuh theming.) Rentang = dua picker tertaut; akhir tak boleh mendahului awal. Keyboard: ←/→ hari, ↑/↓ minggu, PgUp/PgDn bulan, Enter pilih, Esc tutup. Judul kalender menelusuri dua tingkat: hari → bulan → tahun (12 tahun per halaman, sejajar: 2016–2027, lalu 2028–2039), jadi tanggal lahir tak lagi berarti puluhan klik panah. Tiap tingkat di atas grid hari hanyalah navigasi: tak ada yang di-commit sampai sebuah hari dipilih. Butuh freeday-datepicker.js.

Tanggal faktur
Periode laporan
Akhir tak boleh mendahului awal.

Varian ikon (konvensi kit): default (kalender), tanpa ikon lewat data-fdy-no-icon, atau ikon custom dengan <template data-fdy-icon> di dalam wrapper.

Default
Tanpa ikon
Ikon custom

Time picker

Trigger bergaya input + popup daftar waktu (pola listbox WAI-ARIA). Format 24 jam HH:MM; rentang & langkah diatur lewat data-min/data-max/data-step (default tiap 30 menit). Keyboard: ↓ buka, ↑/↓ pindah, Home/End, Enter pilih, Esc tutup. Butuh freeday-timepicker.js.

Jam mulai
Tiap 15 menit, 08:00–17:00

Varian ikon (konvensi kit): default (jam), tanpa ikon lewat data-fdy-no-icon, atau ikon custom dengan <template data-fdy-icon>.

Default
Tanpa ikon
Ikon custom

Datetime picker

Komposisi date picker + time picker jadi satu nilai, memakai ulang dua komponen yang sudah ada, bukan popover monolitik. Composer freeday-datetime.js menyatukan keduanya dan memancarkan satu event fdy-datetime-change (value = YYYY-MM-DDTHH:MM). Varian ikon diwarisi dari tiap picker anak.

Jadwal kirim faktur
Tanpa ikon

File upload

Drop target yang juga membuka dialog berkas saat klik / Enter. State eksplisit: idle, drag-over, mengunggah (progress), selesai, error, karena "tidak terjadi apa-apa" adalah feedback unggah terburuk. Butuh freeday-upload.js. (Demo ini mensimulasikan progress; di app nyata, sambungkan event fdy-upload-add ke fungsi unggahmu.)

Seret berkas ke sini, atau klik untuk memilih PDF hingga 10 MB per berkas

Dua state terminal (statis): terunggah & ditolak:

PO-48213-acme.pdf
248 KB · Terunggah
scan-copy.png
Bukan PDF. Hanya berkas PDF yang diterima.

Stepper / Wizard

Alur multi-langkah: indikator progres (nomor → centang), panel per langkah, tombol Kembali/Lanjut. Langkah yang sudah dilewati bisa diklik untuk ditinjau (linear, tak bisa lompat maju). Butuh freeday-stepper.js.

Langkah bermasalah pakai is-error plus .fdy-step__badge berisi jumlahnya — warna saja tidak membawa pesan apa pun bagi pembaca yang tak bisa melihat merah, jadi jumlah itu disebut juga dalam teks. Meninggalkan langkah bisa ditolak: tombol Lanjut memicu fdy-step-before-change yang bisa dibatalkan, dan validasi yang perlu menunggu server menitipkan promise-nya ke detail.waitFor. Selama promise itu belum selesai, kedua tombol nav dinonaktifkan. Mundur tak pernah ditanya.

Indikator saja (tanpa __btn), dengan langkah kedua bermasalah:

  1. 1Data pelanggan
  2. 2 Item — 3 masalah
  3. 3Ringkasan

Slider

Native <input type="range"> di-tema lewat accent-color, dengan keyboard & ARIA bawaan, fill & thumb otomatis. freeday-slider.js cuma menyalin nilai ke <output>. Warna: primary/accent/danger.

Diskon 15
0%100%
Anggaran 30
Rp 0Rp 100 jt

Rating

Bintang, memakai grup radio native (panah kiri/kanan untuk memilih, ter-asosiasi form). Terisi vs kosong dibedakan isi vs garis (bukan warna saja). Ada varian read-only. Butuh freeday-rating.js.

Autocomplete

Combobox editable: ketik untuk memfilter saran (pola APG combobox + listbox), keyboard ↑/↓/Enter/Esc. Butuh freeday-autocomplete.js. (Opsi statis di-filter di klien; di app nyata, fetch/filter server-side.)

Ketik untuk menyaring; pilih dengan panah + Enter.

Cascade select

Pemilih hierarki (drill-down); model datanya <ul> bersarang tersembunyi: <li> dengan anak <ul> adalah cabang, tanpa anak adalah daun. Cabang membuka level berikut, daun memilih (nilai = jalur lengkap). Keyboard: ↑/↓ pindah, →/Enter masuk cabang / pilih daun, ←/Backspace naik level, Esc tutup. Butuh freeday-cascade.js.

  • Elektronik
    • Handphone
      • Android
      • iOS
    • Laptop
    • Televisi
  • Fashion
    • Pria
    • Wanita
    • Anak
  • Lainnya

Password & mask

Field kata sandi dengan tombol tampil/sembunyi (data-fdy-password, memakai kembali chrome tombol input-group) dan input ber-format saat mengetik (data-fdy-mask: # digit, A huruf, * alnum; karakter lain jadi literal otomatis). Butuh freeday-mask.js.

Form validation

Validasi native (Constraint Validation API) di-wire ke error inline aksesibel: aria-invalid + pesan ter-aria-describedby, fokus ke field invalid pertama saat submit, lalu re-validasi live tiap blur/input. Pesan custom via data-fdy-msg-*, cocokkan antar-field via data-fdy-match. Coba tekan Simpan saat kosong. Butuh freeday-form.js.

Validasi inline

Header + detail (dokumen): .fdy-form-grid + tabel

Rincian item
ItemQtyHargaJumlah
Kertas A4 80gsm1050.000500.000
Tinta Printer Hitam2120.000240.000
TotalRp 740.000

Filter bar

Baris filter yang konsisten: .fdy-filterbar membungkus beberapa .fdy-field. Tiap field ikut ritme lebar (--w-sm · default · --w-lg · --w-xl); satu field --w-grow (biasanya pencarian) menyerap sisa ruang; aksi (__actions) menempel di ujung, sejajar kontrol. Membungkus rapi di layar sempit. Nol JS, cukup layout di atas .fdy-field. Field pencarian di sini memakai data-fdy-search: mencari saat pengetik berhenti sejenak, langsung saat Enter, dan punya tombol kosongkan. Ketiganya berakhir di satu event fdy-search.

Cari
Belum ada pencarian.
Status
Kategori

Select (combobox)

Dropdown berdesain penuh (pola WAI-ARIA APG): popup bisa distyle, keyboard ↑↓/Enter/Esc/ketik. Butuh freeday-select.js. Varian ikon: caret default, tanpa lewat fdy-combo--no-icon, atau custom (--no-icon + .fdy-combo__icon di dalam tombol).

Status faktur (default)
Tanpa ikon
Ikon custom

Checkbox · Radio · Switch

Native <input> distyle, dengan Space, asosiasi label, :focus-visible tetap native. Switch yang labelnya tidak menjelaskan arti "on" diberi hint state: dua baris [data-fdy-when="on|off"] di satu .fdy-help, kit menampilkan yang cocok dengan state sekarang, tanpa JS. Balik switch "Persetujuan" untuk melihatnya.

Setiap perubahan menunggu supervisor. Perubahan langsung berlaku, tanpa ditinjau.

Alert

Pesan inline. Varian danger memakai role="alert".

InfoSinkronisasi terakhir 5 menit lalu.
BerhasilFaktur INV-1042 disimpan.
PerhatianStok barang menipis di 3 gudang.

Toast

Notifikasi sekilas di live-region. Panggil Freeday.toast({variant,title,message}) mengembalikan elemen toast. Beri key agar toast dengan key sama menggantikan yang lama (bukan menumpuk saat error yang sama meletup beruntun); tutup lebih awal dengan Freeday.dismiss(node|key).

Tooltip

Muncul saat hover/focus. Asosiasi via aria-describedby.

Ekspor ke Excel (.xlsx)

Tabs

Pola APG: panah ←/→, Home/End, roving tabindex. Butuh freeday-tabs.js.

Total tagihan Rp 1.240.000, jatuh tempo 30 Juli 2026.

Breadcrumb

Pagination

Table

Tabel semantik statis: <caption>, <th scope>, angka tabular kanan. --striped memberi zebra pada baris genap — warnanya sengaja setengah langkah surface, bukan langkah penuh yang dipakai hover, supaya hover tetap terbaca di baris yang sudah berwarna. Override lewat token --fdy-table-stripe.

Faktur terbaru
FakturPelangganStatusNilai
INV-1042PT Sumber MakmurLunas1.240.000
INV-1043CV Berkah JayaTertunda290.000
INV-1044Toko AmanahDraft0

Data table

Interaktif: cari global, urutkan (klik judul kolom), filter per kolom (ikon corong: teks berisi, enum checklist, angka rentang), pilih baris → bar aksi massal, paginasi. Butuh freeday-table.js.

Daftar faktur (interaktif)
INV-1042PT Sumber MakmurLunas1.240.000
INV-1043CV Berkah JayaTertunda290.000
INV-1044Toko AmanahDraft0
INV-1045UD Maju TerusLunas4.750.000
INV-1046PT Cahaya AbadiTertunda820.000
INV-1047Koperasi SejahteraBatal150.000
INV-1048PT Sumber MakmurLunas3.120.000
INV-1049Toko AmanahDraft67.000
INV-1050CV Berkah JayaLunas1.990.000
INV-1051PT Cahaya AbadiTertunda540.000

Tabel beku (frozen)

Matriks yang dibaca terhadap dua sumbu sekaligus, kurs per mata uang (melintang) per tanggal (menurun), kehilangan maknanya begitu judulnya ter-scroll keluar. .fdy-table--sticky mengganti border-collapse jadi separate supaya garis dipegang oleh sel yang membeku: di bawah collapse, garis antar sel digambar oleh tabel, jadi kolom beku ter-scroll keluar dari garisnya sendiri.

Dua sumbu itu terpisah, dan sengaja: membekukan baris butuh scrollport vertikal, sedangkan tabel pemetaan yang ikut scroll halaman tidak punya, dan memaksakan keduanya jadi satu modifier membuat top:0 menempel di tepi viewport, menutupi app bar. Kolom pakai .fdy-table__freeze + --fdy-freeze-left per sel (offset harus datang dari pemanggil: itu jumlah lebar kolom ter-render, dan CSS tak bisa menjumlahkannya), header pakai .fdy-table--sticky-head di dalam .fdy-table-scroll--frozen yang tingginya diatur --fdy-table-frozen-h.

Kurs harian per mata uang
Tanggal USDEUR SGDJPY AUDGBP CNYMYR
01 Jul16.24017.61012.01010110.78020.6402.2353.440
02 Jul16.25517.58812.02410110.80220.6112.2383.446
03 Jul16.19817.64011.99810010.75520.7022.2313.431
04 Jul16.30117.52212.07710210.84420.5602.2443.459
05 Jul16.27717.55912.04110110.81920.5882.2403.452
08 Jul16.15017.70111.96210010.71120.7802.2263.421
09 Jul16.21217.63312.00510110.76920.6672.2333.437

Scroll ke kanan dan ke bawah: kolom tanggal dan baris judul tetap, dengan garisnya.

Kolom beku memakai ground body, bukan ground header: tanpa itu, baris yang di-hover terputus di garis beku dan pelacakan baris melintasi grid lebar hilang, padahal itu justru alasan membekukannya.

States

Placeholder kosong / error untuk area data.

Belum ada faktur
Faktur yang kamu buat akan muncul di sini.
Gagal memuat
Tidak bisa mengambil data dari server.

Charts

Sparkline, bar, line, area, dan donut, semuanya SVG/CSS murni tanpa dependency. Seri tunggal via data-values; multi-seri via data-series (JSON). Cartesian (line/area/bar) menggambar sumbu ber-tema (--chart-grid/--chart-tick), legenda otomatis untuk ≥2 seri, dan format nilai data-fdy-format="number|percent|currency". Warna dari token → chart ikut re-warna saat data-theme berubah. Multi-seri memakai palet kategorikal tervalidasi --chart-1…--chart-8 (urutan tetap); override lewat data-fdy-colors, memakai nama token semantik (primary…) atau slot chart-1…chart-8 untuk mengunci warna per kategori. Untuk data reaktif: panggil FreedayChart.update(el) atau pakai <FdyChart> dari @cahyo-dimas/freeday/vue. Butuh freeday-chart.js; tiap chart role="img" + aria-label + fallback tabel di dalam elemen.

Pendapatan

6 bulan terakhir

Rp 18 jt

Faktur / hari

Status faktur

Posting vs draft

Line multi-seri · sumbu persen

Nilai faktur

Area · sumbu USD

Faktur per kanal

Bar bertumpuk (stacked)

Tree view

Hierarki lewat <details> native, buka/tutup dengan klik atau Enter/Space, tanpa JS. Cabang bisa dilipat; daun = baris biasa. Varian checkbox (kanan) menambah pilihan bertingkat: centang cabang → semua anak ikut; sebagian anak → cabang jadi indeterminate. Butuh freeday-tree.js untuk cascade; centang tak pernah membuka/menutup cabang.

Dasar (tanpa JS)

  • Pelanggan
    • Jakarta
      • PT Sumber Makmur
      • PT Cahaya Abadi
    • Bandung
      • CV Berkah Jaya
  • Item
    • Kertas A4 80gsm
    • Tinta Printer Hitam

Dengan checkbox (cascading)

  • Pelanggan
    • Jakarta
      • PT Sumber Makmur
      • PT Cahaya Abadi
    • Bandung
      • CV Berkah Jaya
  • Item
    • Kertas A4 80gsm
    • Tinta Printer Hitam

Card

__head menaruh tanda, judul, dan jalan keluar kartu dalam satu baris; kartu terakhir di sini juga menunjukkan .fdy-state--compact --danger untuk muatan yang gagal. --interactive = kursor + hover-lift untuk kartu yang diberi handler klik. Modifier ini presentasional: CSS tak bisa tahu handler-nya ada; pasangkan dengan kontrol nyata, biasanya .fdy-btn--stretch yang membentangkan area kliknya ke seluruh kartu. Kalau kartunya adalah kontrol (baris pemilih yang keyboard-reachable & diumumkan), render sebagai <button> dan tambah --button untuk me-reset kotak tombol UA tanpa membuang surface/border kartu.

Workspace Alpha

Satu kartu, satu aksi utama, satu pintu keluar. Klik di mana saja → tombol utama; "Detail" tetap miliknya sendiri.

Faktur INV-1042

Jatuh tempo 30 Juli 2026. Total tagihan Rp 1.240.000.

Interactive

Arahkan kursor dan kartu terangkat (hover-lift).

Jatuh tempo hari ini

Gagal memuat antrean. Angka nol di sini tidak berarti tidak ada pekerjaan.

Badge

Inline untuk status; overlay untuk angka/dot yang menempel di sudut ikon, tombol, atau teks.

Varian semantik (--success, --warning, --danger, --info) menyatakan penilaian: lunas itu baik, batal itu buruk. Untuk kategori yang tak punya penilaian (jenis dokumen, departemen, kanal), pakai skala tone --tone-1…--tone-8: warnanya membedakan tanpa menyiratkan apa pun, dan tidak mencuri arti hijau/merah dari status yang benar-benar butuh.

Faktur Retur Pesanan Pengiriman Kuitansi Jurnal Kontrak Lainnya
Baru Lunas Tertunda Batal Draft Arsip

Badge notifikasi = overlay. Bukan komponen terpisah dari “surat”: angka/“99+”/ikon/titik yang menempel di sudut elemen apa pun: lonceng, amplop, avatar, atau tombol. Bungkus konten dengan .fdy-badge-wrap, tambahkan .fdy-badge-ov. Warna ber-teks AA (default gelap · primary · danger); titik untuk accent/info/success/warning.

Bug Reports

Avatar

Ukuran --sm / default / --lg, plus grup bertumpuk. Untuk membedakan avatar berinisial sama (mis. banyak nama "PT …"), pakai --tone-1…--tone-8 adalah tint dekoratif yang tetap kontras AA di terang & gelap; hash indeks stabil dari nama lengkap (bukan dari inisial).

SM BJ TA SM BJ TA
PT PT PT PT PT PT PT PT

Chip

Tiga peran: default / hapus (tag statis atau filter aktif yang bisa dihapus), choice (toggle pilih), dan filter (toggle dengan centang). Yang interaktif = <button aria-pressed> dikelola freeday-chip.js: bungkus dalam data-fdy-chips, tambah data-single untuk pilih-satu.

Semua Status: Lunas Bulan: Juli

List (baris rata)

Container rata untuk baris: satu permukaan ber-border, pembatas hairline, tanpa shadow. Ini yang dipakai saat .fdy-datatable berubah jadi daftar di bawah md, bukan tumpukan .fdy-card, yang memakai --shadow-lift sehingga sepuluh baris jadi sepuluh objek mengapung. Baris bisa jadi kontrol: render sebagai <button> + --button. Nol JS.

  • Globex Supply INV-2043 · draft 0

Beda dari .fdy-list-reset (utilitas yang cuma membuang bullet/indent bawaan browser).

Daftar terurut (seret)

Ubah urutan dengan menyeret pegangan, atau fokus ke pegangan lalu tekan ↑ / ↓. Garis menunjukkan tempat baris akan mendarat, dan tak ada yang berpindah sebelum tombol dilepas; Escape membatalkan. fdy-sort-change dapat dibatalkan: halaman statis membiarkannya dan kit memindah elemennya, framework membatalkannya lalu mengurutkan state-nya sendiri. Baris data-fdy-sort-fixed tak bisa dilewati. Butuh freeday-sortable.js.

  • Area Utara3 titik patroli
  • Area Selatan4 titik patroli
  • Gerbang utama2 titik patroli
  • Lainnyaselalu terakhir

Detail (key-value)

Tampilan ringkas untuk halaman detail faktur / pelanggan. Nilai yang dibawa pembaca ke tempat lain (nomor dokumen, ID event) diberi tombol salin: data-fdy-copy="<nilai>" menyalin nilainya lalu memberi toast, termasuk saat clipboard tidak tersedia (http).

Faktur INV-1042

Pelanggan
PT Sumber Makmur
Status
Lunas
Jatuh tempo
30 Juli 2026
Total
Rp 1.240.000
ID referensi
EVT-7F3A-0042

Pelanggan

Nama
PT Sumber Makmur
Email
pengadaan.kepala-divisi@sumbermakmur-internasional.co.id
Telepon
0812345678901

Progress & Spinner

Busy overlay

Menghalangi layar selama operasi yang tak boleh diinterupsi atau dikirim dua kali. Imperatif saja — Freeday.busy({ caption, delay, mark }) dan Freeday.idle() — karena API komponen mengundang dua instans, dan dua scrim dengan dua caption adalah persis kegagalan yang komponen ini cegah. Bukan dialog: tak ada yang ditanyakan dan tak ada yang bisa ditutup, interaksi dicabut dengan inert pada sisa halaman. Muncul setelah jeda 120 ms secara default, supaya operasi 80 ms tak sempat mengedipkan scrim.

Skeleton

--title/--text untuk teks, --circle untuk bentuk bulat, dan --avatar (+--avatar-sm/--avatar-lg) yang seukuran .fdy-avatar, jadi placeholder memesan kotak yang persis sama dan tak ada geser tata letak saat data datang.

Timeline

Feed peristiwa vertikal: titik penanda pada garis penghubung, dengan waktu & deskripsi. Warna titik menandai status (didampingi teks, bukan warna saja). Pure CSS.

  1. 21 Jul 2026 · 09:12

    Faktur dibuat

    INV-1042 untuk PT Sumber Makmur, Rp 1.240.000.

  2. 21 Jul 2026 · 09:15

    Dikirim ke pelanggan

    Email terkirim ke finance@sumbermakmur.co.id.

  3. 25 Jul 2026 · 14:30

    Jatuh tempo mendekat

    Sisa 5 hari sebelum jatuh tempo.

  4. 28 Jul 2026 · 10:02

    Lunas

    Pembayaran diterima via transfer bank.

App bar

Bar atas standalone: brand · aksi · spacer. Bisa sticky, elevated, dense, atau berwarna. Tombol hamburger biasanya membuka drawer (menu samping).

Freeday
CD

Berwarna (primary) & dense, kontrol jadi on-color.

Faktur

Product appbar: komposisi kaya di dalam .fdy-app__topbar (App shell), beda dari .fdy-appbar berdiri sendiri di atas. Urutan: nav toggle → .fdy-breadcrumb → judul halaman (.fdy-app__title, auto-spacer kanan) → pencarian (.fdy-input-group + __addon--icon) → menu pengguna (.fdy-menu). Salin blok ini langsung ke dalam <header class="fdy-app__topbar"> shell Anda.

INV-1042

Vue/React: useFreeday menghidrasi .fdy-menu otomatis lewat enhancer data-fdy-menu (mekanisme sama dengan freeday-menu.js vanilla), jadi cukup pasang markup di atas di dalam komponen, tak perlu wiring buka/tutup manual.

Sidebar menu

Menu navigasi vertikal dari .fdy-nav (dipakai App shell & sidebar dokumentasi ini). Tiap node bebas: ikon + teks, teks saja, atau tambah badge angka. .fdy-nav__group = seksi collapsible; .fdy-nav__tree = item bersarang; dua-duanya native <details> (zero-JS, keyboard bawaan). Di App shell, sidebar jadi off-canvas drawer di mobile.

Drawer

Panel samping temporary (overlay + backdrop) di atas <dialog> native, dengan focus-trap, Esc, dan kembalikan-fokus gratis. Kiri atau kanan. Slide masuk & keluar dengan backdrop yang mem-blur. Tutup lewat Esc/backdrop untuk melihat animasi keluarnya. Butuh freeday-drawer.js. (Tombol hamburger di App bar di atas juga membukanya.)

Menu
Filter
Status

Accordion

Native <details>, zero-JS dan aksesibel bawaan. Panel me-reveal (fade + rise) saat dibuka; chevron ikut berputar.

Info pengiriman
Dikirim via JNE, estimasi 2–3 hari kerja.
Metode pembayaran
Transfer bank, virtual account, atau kartu kredit.
Kebijakan retur
Retur diterima maksimal 7 hari setelah barang sampai.

Divider · Kbd

Bagian atas


Bagian bawah

Simpan cepat dengan Ctrl + S, tutup dialog dengan Esc.

Modal

Native <dialog>, dengan focus-trap, Esc, dan backdrop gratis dari browser. Muncul & menghilang dengan fade + skala halus (backdrop ikut mem-blur), simetris masuk-keluar. Untuk pertanyaan ya/tidak tidak perlu merakit dialog sendiri: await Freeday.confirm({ title, message, details, acceptText, tone }) menjawab true / false, dan Esc atau klik backdrop berarti tidak.

Hapus faktur?

Faktur INV-1042 akan dihapus permanen. Tindakan ini tidak bisa dibatalkan.

Contoh: satu layar bisnis

Semua komponen dirakit jadi layar faktur nyata.

Lewati ke konten utama

Faktur

Daftar faktur
FakturPelangganStatusNilai
INV-1042PT Sumber MakmurLunas1.240.000
INV-1043CV Berkah JayaTertunda290.000

Faktur baru

Status

Teks enhancer (i18n)

Tiap string yang ditulis enhancer vanilla berbahasa Inggris sejak 2.0.0, sama dengan wrapper typed-nya. Sebelum itu default-nya Indonesia, dan aplikasi yang memakai dua jalur sekaligus jadi terbaca seperti dua produk. Sejak 1.39.0 setiap enhancer menyimpan teksnya dalam satu tabel TEXT yang dibaca lewat textOf(), jadi semuanya bisa diganti per elemen dengan data-fdy-text-<key>, tanpa fork dan tanpa merender ulang node-nya sendiri. Itu pula jalur migrasi buat aplikasi berbahasa Indonesia.

Placeholder {n}, {from}, {to}, {total}, {name}, {max} dan {label} disubstitusi bila string-nya mendukung. Pesan validasi memakai bentuk sama pada <form> (data-fdy-text-required, …), lebih longgar dari data-fdy-msg-<alias> per field yang tetap menang. Freeday.toast() menerima closeLabel lewat objek opsinya. Komponen bertipe Vue/React/Blazor sudah English dan tak butuh ini.

Enhancer strings overridden to English
INV-1042PT Sumber Makmur1,240,000
INV-1043CV Bangun Jaya880,000
INV-1044PT Andalan Niaga2,310,000
INV-1045UD Terang Abadi415,000
INV-1046PT Cahaya Timur1,690,000

Tabel yang sama dengan di atas; hanya atributnya yang berbeda. Buka corong filter pada kolom Customer: judul dan tombolnya ikut English.

Adapter Blazor menjangkau enhancer ini lewat FreedayBlazor.initAll, yang menjalankan semua enhancer terdaftar. Itulah kenapa jangkauan ini penting, dan kenapa default-nya tetap tidak berubah. npm test menjaga tak ada string enhancer yang ditulis di luar tabel TEXT-nya, jadi string baru datang dalam keadaan bisa di-override atau tidak sama sekali.

Breakpoint

Utilitas tampilan responsif + provider JS. Skala (min-width): sm 600 · md 960 · lg 1280 · xl 1920. Kelas .fdy-hide-below-* / .fdy-hide-above-* menyembunyikan per rentang. freeday-breakpoint.js menstempel <html data-breakpoint> + memancarkan fdy-breakpoint-change. Ubah ukuran jendela untuk melihatnya.

Breakpoint saat ini: …

Terlihat di md ke atas (≥ 960px), konten desktop
Terlihat di bawah md (< 960px), konten mobile

Aksesibilitas

Kontrak yang dipegang setiap komponen, bukan renungan belakangan.

  • Kontras teks & kontrol lolos WCAG AA di tema terang & gelap.
  • :focus-visible selalu terlihat, outline/ring 2–3px.
  • Status tak hanya lewat warna (ikon/teks pendamping).
  • HTML native dulu; ARIA hanya saat native tak cukup.
  • Komponen interaktif ikut pola WAI-ARIA APG (role/aria/keyboard).
  • Modal & dialog: focus-trap, Esc, fokus kembali ke pemicu.
  • Input error: aria-invalid + aria-describedby.
  • Menghormati prefers-reduced-motion.
  • Target sentuh memadai; label jelas pada tiap kontrol.