Feedback & States — UI/UX

UI States — Komunikasikan Status ke User Setiap elemen UI memiliki berbagai state. User harus selalu tahu apa yang sedang terjadi. 5 State yang Harus Didesain…

Feedback adalah cara halaman memberi tahu apa yang sedang terjadi, setiap saat: sedang memuat, kosong, gagal, berhasil. State (keadaan) adalah tiap kemungkinan wujud halaman itu. Bayangin memesan di warung. Kamu bilang "nasi goreng satu", dan Bu warung menjawab "siap, ditunggu ya". Kamu melihat wajannya mulai berasap, lalu piringnya datang. Kalau nasinya habis, dia bilang "maaf, nasinya habis, mie goreng mau?". Kalau dia diam saja setelah kamu memesan, kamu gak tahu pesananmu didengar, dan kamu memesan sekali lagi.

🧪 Tebakan cepat: Pak Hadi menekan "Pesan kamar, bayar di tempat". Tombolnya cuma berubah abu-abu, tanpa tulisan apa pun, dan 3 detik kemudian muncul "Pesanan terkirim". Halamannya bekerja. Apa yang salah? Jawabannya ada di bagian "Tombol Pesan saat menunggu".

Enam keadaan yang harus didesain

Desainer sering cuma menggambar halaman yang berhasil dan penuh data. Padahal tiap bagian halaman punya lima keadaan dasar, ditambah satu untuk koneksi. Ini semuanya di halaman pesan Homestay Kabut:

Keadaan Kapan Di halaman Bu Sri
Loading menunggu data atau jawaban daftar kamar: skeleton; tombol Pesan: "Memesan..."
Empty datanya memang gak ada "Gak ada kamar kosong 12 Des." dengan tombol "Lihat 13 Des"
Error permintaan gagal "Pesanan belum terkirim. Coba lagi." Pilihan malam tetap seperti tadi
Success permintaan berhasil "Pesanan terkirim. Bu Sri akan konfirmasi lewat WhatsApp."
Partial sebagian berhasil foto kamar gagal dimuat, tapi harga dan tombol Pesan tetap jalan
Offline gak ada koneksi "Kamu sedang offline. Pesananmu belum terkirim."

Lima yang pertama (empty, loading, error, success, partial) adalah state yang harus didesain untuk tiap elemen yang memuat data. Offline adalah error khusus yang pantas punya pesannya sendiri, karena penyebab dan jalan keluarnya beda: bukan "coba lagi", tapi "sambungkan internet dulu".

Pesan yang baik menyebut apa yang terjadi dan apa langkah berikutnya. "Error 500" gak membantu siapa pun; "Pesanan belum terkirim. Coba lagi." membantu, apalagi dengan tombol "Coba lagi" di sampingnya.

Berapa lama menunggu, indikator apa

Jakob Nielsen (Usability Engineering, 1993) memberi tiga batas waktu yang masih dipakai sampai sekarang: 0,1 detik terasa instan, 1 detik masih menjaga alur pikiran, 10 detik adalah batas orang mau tetap fokus menunggu. Dari situ, Nielsen Norman Group (Katie Sherwin, 2014) menyarankan:

Lama menunggu Indikator
di bawah 1 detik gak perlu indikator
2 sampai 10 detik animasi berulang: spinner atau skeleton
lebih dari 10 detik progress bar yang menunjukkan persen selesai

Untuk 2 sampai 10 detik, pilihannya tergantung apa yang dimuat (NN/g, Samhita Tankala, 2023):

Tombol Pesan saat menunggu

<button class="book" id="book">Pesan kamar, bayar di tempat</button>
<p id="status" role="status"></p>
<p id="error" class="error" role="alert"></p>

<script>
  const book = document.querySelector('#book');
  book.addEventListener('click', async () => {
    if (book.getAttribute('aria-disabled') === 'true') return; // cegah pesan dua kali
    book.setAttribute('aria-disabled', 'true');
    book.textContent = 'Memesan...';
    try {
      await kirimPesanan(); // fetch ke server Bu Sri
      document.querySelector('#status').textContent = 'Pesanan terkirim. Bu Sri akan konfirmasi lewat WhatsApp.';
    } catch {
      document.querySelector('#error').textContent = 'Pesanan belum terkirim. Coba lagi.';
    } finally {
      book.setAttribute('aria-disabled', 'false');
      book.textContent = 'Pesan kamar, bayar di tempat';
    }
  });
</script>

Jadi jawaban tebakannya: gak ada loading feedback. Tombol abu-abu tanpa tulisan bisa berarti "sedang diproses", bisa juga "tombolnya mati". Pak Hadi gak tahu ketukannya terdaftar, dan 3 detik itu ada di zona yang butuh indikator. Itu jawaban tebakannya.

aria-live: kabar yang dibacakan

Pengguna screen reader gak melihat tulisan "Pesanan terkirim" muncul. Live region membuat perubahan teks di dalamnya dibacakan otomatis, dan WCAG 4.1.3 (Status Messages, level AA) memintanya untuk pesan seperti ini:

Taruh live region-nya, kosong, sejak halaman dimuat, lalu isi teksnya saat ada kabar. Screen reader memantau region yang sudah ada; region yang ditambahkan bersamaan dengan teksnya sering gak dibacakan.

Untuk kolom isian yang salah, polanya sama, ditambah dua atribut:

<label for="hp">Nomor HP</label>
<input id="hp" class="input-error" aria-invalid="true" aria-describedby="hp-error">
<span id="hp-error" class="error-msg" role="alert">Nomor HP harus diawali 08.</span>

<style>
  .input-error { border: 1px solid #EF4444; }  /* 3,76:1, cukup untuk garis (minimal 3:1) */
  .error-msg { color: #b91c1c; }               /* 6,47:1, cukup untuk teks (minimal 4,5:1) */
</style>

⚠️ Jebakan yang sering ketemu

TL;DR: Desain enam keadaan, bukan cuma sukses: loading, empty, error, success, partial (lima state dasar), plus offline. Batas waktu Nielsen: 0,1 detik terasa instan, 1 detik menjaga alur, 10 detik batas fokus; di atas 1 detik beri indikator, spinner atau skeleton untuk 2 sampai 10 detik, progress bar di atas 10 detik. Skeleton screen lebih baik untuk memuat halaman atau daftar; spinner untuk satu aksi. Tombol yang menunggu mengubah tulisannya ("Memesan...") dan memakai aria-disabled, bukan disabled yang membuang fokus. Kabar sukses di role="status", error di role="alert" (WCAG 4.1.3), region-nya ada sejak awal. Kolom yang salah: aria-invalid="true", aria-describedby ke id pesannya, border-color: #EF4444, dan teks pesan #b91c1c.

Yang akan kamu pelajari