Button adalah janji: "tekan aku, dan ini yang terjadi". CTA (call to action) adalah button untuk aksi utama halaman, di halaman Bu Sri "Pesan kamar, bayar di tempat". Bayangin panel tombol di lift. Tombol lantai disusun rapi, tombol darurat dibedakan, tiap tombol cukup besar untuk jari, tulisannya bilang apa yang terjadi, dan tombol yang ditekan langsung menyala sampai lift tiba. Kalau gak menyala, orang menekannya lagi dan lagi.
🧪 Tebakan cepat: Sinyal Pak Hadi lemah. Dia menekan "Pesan kamar", dan selama 1,5 detik tombolnya terlihat sama persis. Dia menekan sekali lagi. Berapa pesanan yang sampai ke Bu Sri? Jawabannya ada di bagian "Enam keadaan".
Hierarki: satu primary per layar
Dari pelajaran prioritas warna: tiap layar punya satu aksi utama, dan aksi lain dibedakan dari beratnya.
| Level | Tampilan | Di kartu pesan Bu Sri |
|---|---|---|
| Primary | solid hijau #15803d, teks putih (5,02:1) |
"Pesan kamar, bayar di tempat" |
| Secondary | garis dan teks hijau, latar putih | "Tanya Bu Sri lewat WhatsApp" |
| Tertiary (ghost) | teks saja, tanpa latar dan garis | "Lihat aturan batal lengkap" |
Tertiary sering disebut ghost karena gak punya badan, cuma tulisan. Jadi tiga levelnya: primary, secondary, ghost (atau tertiary).
Di latihan nanti, tiga level yang sama memakai biru: .btn-primary dengan background-color: #2563EB, color: white, font-weight: 600 (putih di atas biru 5,17:1); .btn-secondary dengan teks #2563EB di atas latar transparan dan garis 1px solid #2563EB; .btn-ghost dengan teks abu #6B7280 (4,83:1), latar transparan, tanpa garis.
Enam keadaan
.btn { padding: 11px 16px; font: inherit; font-weight: 600; line-height: 24px; border: 1px solid transparent; border-radius: 8px; cursor: pointer; }
.btn-primary { color: #fff; background-color: #15803d; } /* default */
.btn-primary:hover { background-color: #166534; } /* mouse di atasnya */
.btn-primary:active { background-color: #14532d; } /* sedang ditekan */
.btn:focus-visible { outline: 3px solid #1f2937; outline-offset: 2px; } /* fokus keyboard */
.btn-primary:disabled { color: #475569; background-color: #e2e8f0; cursor: not-allowed; } /* nonaktif */
.btn-primary[aria-busy="true"] { background-color: #14532d; cursor: progress; } /* memuat */
- Default: keadaan diam. Hover: lebih gelap saat mouse di atasnya (HP gak punya hover). Active: paling gelap selama ditekan.
- Focused: cincin 3px saat tombol dipilih dengan Tab. Jangan dihapus dengan
outline: none. - Disabled: abu-abu, bukan hijau pucat, karena gak bisa ditekan (
#475569di atas#e2e8f0, 6,15:1). Tomboldisabledjuga gak bisa difokus dengan Tab, jadi tulis alasannya di dekatnya: "Pilih jumlah malam dulu." - Loading: setelah ditekan, sampai server menjawab.
Lima keadaan pertama (default, hover, active, focused, disabled) wajib untuk tiap button. Loading wajib untuk button yang mengirim sesuatu:
const book = document.querySelector(".book");
book.addEventListener("click", async () => {
if (book.getAttribute("aria-busy") === "true") return; // ketukan kedua diabaikan
book.setAttribute("aria-busy", "true");
book.textContent = "Memesan...";
await kirimPesanan(); // kirim ke server
book.removeAttribute("aria-busy");
book.textContent = "Pesan kamar, bayar di tempat";
});
- Tombol langsung berubah jadi "Memesan...", jadi Pak Hadi tahu ketukannya diterima.
- Selama
aria-busy="true", ketukan berikutnya diabaikan. Di Lab, dua ketukan cepat tetap menjadi satu pesanan. - Tombolnya selebar kartu, jadi lebarnya gak berubah saat tulisannya jadi lebih pendek. Tombol yang mengecil saat memuat menggeser isi di sekitarnya.
Tanpa keadaan memuat, tombol terlihat sama, Pak Hadi menekan lagi, dan tiap ketukan mengirim satu pesanan. Jadi jawaban tebakannya: dua pesanan, untuk malam yang sama. Itu jawaban tebakannya.
Ukuran dan target sentuh
Tinggi button = padding atas + tinggi baris + padding bawah + garis. Dengan line-height: 24px dan garis 1px, diukur sama di Chromium, WebKit, dan Firefox:
| Ukuran | Padding atas dan bawah | Tinggi | Cocok untuk |
|---|---|---|---|
| Small | 3px | 32px | aksi kecil di baris tabel, di laptop |
| Medium | 7px | 40px | form di laptop |
| Large | 11px | 48px | CTA, dan semua button di HP |
Batasnya dari pelajaran density: WCAG 2.5.8 minimal 24 × 24px (level AA), Apple 44 × 44pt, Material 48 × 48dp. Di HP pakai 48px. Tombol pesan Bu Sri setinggi 48px dan selebar kartu (311px di HP 375px), jadi gampang dijangkau jempol.
Label: kata kerja di depan
Label button bilang apa yang terjadi saat ditekan, dimulai dengan kata kerja:
| Kurang jelas | Lebih jelas | Kenapa |
|---|---|---|
| Submit, OK | Pesan kamar | tamu tahu yang terjadi: kamar dipesan |
| Klik di sini | Tanya Bu Sri lewat WhatsApp | menyebut tujuannya |
| Ya / Tidak | Batalkan pesanan / Kembali | tiap label bisa dibaca tanpa pertanyaannya |
Pendek itu baik (1 sampai 3 kata), tapi jelas lebih penting. "Pesan kamar, bayar di tempat" lebih panjang dari "Pesan", tapi juga menjawab kekhawatiran tamu: belum perlu membayar sekarang.
Pilih elemennya dari yang terjadi: <button> untuk aksi di halaman ini (memesan), <a href> untuk pindah tempat (membuka WhatsApp, membuka halaman aturan batal), walaupun tampilannya seperti tombol.
⚠️ Jebakan yang sering ketemu
- Tiga tombol solid. Gak ada yang dilihat duluan. Satu primary, sisanya secondary dan ghost.
- Gak ada keadaan memuat. Tamu menekan dua kali, dan pesanan terkirim dua kali.
- Disabled hijau pucat tanpa alasan. Masih terlihat bisa ditekan, dan tamu gak tahu kenapa gak bisa. Abu-abu, ditambah teks alasannya.
- Button 32px di HP. Lolos 24px WCAG, tapi gampang meleset. Pakai 48px.
- Label "Submit" atau "OK". Bilang aksinya: "Pesan kamar".
TL;DR: Hierarki button ada tiga level: primary (solid, satu per layar), secondary (bergaris), dan ghost atau tertiary (teks saja). Di latihan: .btn-primary background-color: #2563EB, color: white, font-weight: 600; .btn-secondary color: #2563EB; .btn-ghost color: #6B7280. Tiap button punya lima keadaan wajib: default, hover, active, focused (:focus-visible, jangan outline: none), dan disabled (abu-abu, dengan alasan tertulis); button yang mengirim sesuatu juga butuh loading (aria-busy="true", "Memesan...", ketukan kedua diabaikan) supaya pesanan gak terkirim dua kali. Tinggi = padding + line-height + garis: 32, 40, atau 48px; di HP 48px (Material 48dp, Apple 44pt, WCAG 2.5.8 minimal 24px). Label dimulai kata kerja dan bilang yang terjadi: "Pesan kamar", bukan "Submit".