Merancang momen ketika hal-hal tidak berjalan mulus: halaman 404 dan error, empty state yang bermakna, loading dengan skeleton, serta pola pemulihan undo dan retry, lengkap dengan praktik membuat state kit lengkap beserta copy-nya untuk KasirKita.

Setelah di episode 19 kita memperkuat bahasa antarmuka, pada episode ini kita merancang momen kegagalan dan kekosongan — error, 404, empty, loading — plus cara pengguna pulih dari semuanya. Ini bagian yang paling sering dilupakan, padahal justru di sinilah kualitas produk diuji.
Mengapa penting? Pengguna mengingat momen buruk lebih lama daripada momen biasa. Transaksi yang gagal di kasir, stok yang hilang tanpa penjelasan, atau halaman yang "hang" tanpa indikasi — semua momen itu menentukan apakah Bu Sari besok masih memakai KasirKita. Desain state yang baik mengubah kepanikan menjadi ketenangan.
Error yang baik punya struktur jelas (dari episode 19): apa yang salah → mengapa → jalan keluar. Untuk halaman penuh:
┌──────────────────────────────────┐
│ [ ⚠️ ikon ] │
│ Gagal memuat laporan │ apa yang salah
│ Koneksi ke server bermasalah. │ mengapa
│ Data di perangkatmu tetap aman. │ meyakinkan
│ [ Coba Lagi ] [ Lihat Offline ]│ jalan keluar
└──────────────────────────────────┘404 adalah halaman yang paling sering jadi "tempat pembuangan" — halaman tanpa desain. Padahal 404 adalah momen pengguna tersesat; ia harus membantu pulang:
Empty state (detail di episode 10 & 19) mengikuti formula situasi → alasan → aksi. Dalam state kit, siapkan variannya:
| Konteks | Empty state yang baik |
|---|---|
| Stok kosong | "Belum ada produk. Tambahkan produk pertamamu untuk mulai memantau stok." + [Tambah Produk] |
| Rekap kosong | "Belum ada transaksi hari ini." + [Mulai Transaksi] |
| Pencarian kosong | "Tidak ditemukan produk 'roko'." + saran [Lihat semua produk] |
| Notifikasi kosong | "Belum ada notifikasi. Kami kabari saat stok menipis." |
Perhatikan: bahkan empty state pencarian diberi informasi yang berguna (saran), bukan sekadar "hasil tidak ditemukan".
Skeleton (placeholder berbentuk konten) lebih baik daripada spinner untuk memuat data — ia memberi antisipasi bentuk konten dan terasa lebih cepat:
<div class="skeleton-card" aria-busy="true" role="status">
<div class="skel-block" style="height: 96px; width: 100%;"></div>
<div class="skel-block" style="height: 14px; width: 60%;"></div>
<div class="skel-block" style="height: 14px; width: 40%;"></div>
</div>Aturan loading:
role="status" / aria-busy) — pengguna tunanetra perlu tahu data sedang dimuat.Pemulihan adalah jaring pengaman yang membuat pengguna berani bertindak:
Undo menghilangkan ketakutan akan kesalahan. Kasus klasik: pengguna salah menghapus item dari transaksi.
Retry memulihkan kegagalan sementara (jaringan, server):
Tip
Pilih antara konfirmasi vs undo berdasarkan konsekuensi & frekuensi: aksi destruktif permanen (hapus akun) → modal konfirmasi; aksi yang sering terjadi & bisa dibatalkan (hapus item, hapus produk) → undo. Undo lebih cepat bagi pengguna yang sedang terburu-buru di kasir.
Bangun State Kit di design system KasirKita:
role, aria-live, aria-busy).Warning
Jangan sembunyikan kegagalan dengan memutar-mutar spinner tanpa batas, atau menampilkan layar kosong tanpa pesan. Pengguna lebih rela mendengar "terjadi masalah" dengan jelas daripada menunggu selamanya dalam ketidakpastian. Ketidakpastian adalah UX failure yang paling sering terabaikan.
Pada episode 20 ini, kalian telah merancang state kit lengkap untuk momen-momen tidak ideal.
Inti yang harus dibawa pulang:
Di episode 21 selanjutnya kita akan menghidupkan state-state ini dengan gerakan yang bermakna: motion design & micro-interactions — timing, easing, durasi, dan preferensi reduced-motion untuk KasirKita. Sampai jumpa di episode 21!