Kolom pencarian toko Budi punya kebiasaan kecil yang membuat pengunjung betah: begitu tombol Enter ditekan, pencarian langsung dikirim tanpa perlu menekan tombol cari dengan mouse. Sementara itu, Siti sedang membangun aplikasi catatan dan ingin meniru pintasan yang ia pakai setiap hari — Ctrl+S untuk menyimpan, bukan untuk memunculkan dialog simpan bawaan browser. Kedua fitur itu berdiri di atas hal yang sama: membaca peristiwa papan ketik.
Peristiwa keyboard bekerja agak berbeda dari klik. Peristiwanya tidak selalu terikat satu tombol yang jelas terlihat — ia mengikuti elemen yang sedang fokus, dan satu kali menekan tombol bisa memicu banyak peristiwa sekaligus. Chapter ini membahas pasangan keydown dan keyup, membedakan event.key dari event.code yang sering tertukar, membaca tombol pengubah seperti Ctrl dan Shift, serta menangani tombol yang ditahan (repeat). Seluruh keluaran diuji lewat jsdom dengan simulasi penekanan tombol nyata.
keydown dan keyup #
Setiap interaksi papan ketik menghasilkan dua peristiwa utama: keydown saat tombol ditekan, dan keyup saat tombol dilepas. Peristiwa-peristiwa itu dikirim ke elemen yang sedang menerima fokus — sebuah kolom <input>, misalnya — dan bila tidak ada elemen yang fokus, peristiwanya diterima document. Berikut kolom pencarian milik Budi beserta dua listener-nya:
<input id="kolom-cari" type="text">// papan-ketik.js — merespons keydown dan keyup pada kolom pencarian
const kolomCari = document.querySelector("#kolom-cari");
kolomCari.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
console.log(`Cari: "${kolomCari.value}"`);
}
});
kolomCari.addEventListener("keyup", function (event) {
console.log(`keyup: "${event.key}" dilepas`);
});Simulasi kita meniru tiga aksi pengguna: nilai kolom sudah berisi hasil mengetik "belajar dom", lalu pengguna menekan tombol b (keydown lalu keyup), dan terakhir menekan Enter. Keluaran berikut dicatat dari eksekusi nyata berkas ini di lingkungan DOM jsdom.
Output yang Dihasilkan (console browser):
keyup: "b" dilepas
Cari: "belajar dom"Mari kita telaah:
- Baris 4–8 (listener
keydown): handler ini hanya bereaksi pada satu tombol:event.key === "Enter". Karena itu keydown untukbtidak mencetak apa pun — seleksi tombol dilakukan di dalam handler, bukan di pendaftarannya. - Baris 6 (
kolomCari.value): saatEnterditekan, isi kolom dibaca langsung dari propertivalue— teks yang diketik pengguna sampai detik itu. - Baris 10–12 (listener
keyup): listener ini mencatat setiap tombol yang dilepas, sehingga keyupbtampak di baris pertama keluaran. Pola “keydown memutuskan, keyup memberi tanda selesai” lazim dipakai untuk kontrol permainan dan efek tekan-tahan.
Peristiwa Keyboard Mengikuti Fokus #
Satu mekanisme menentukan siapa yang menerima peristiwa keyboard: elemen yang sedang menerima fokus. Kolom <input> yang aktif menerimanya, tombol yang baru ditekan menerimanya, dan bila tidak ada elemen yang fokus, peristiwa diterima document — itulah sebabnya listener pintasan global pada berkas kedua dipasang di sana. Elemen yang tidak lazim difokuskan bisa dibuat fokusable lewat atribut tabindex, membuka pintasan keyboard bagi komponen kustom seperti daftar yang dinavigasi panah.
Perlu dicatat pula bahwa mengetik di kolom teks tidak hanya menghasilkan keydown dan keyup: setiap perubahan nilai juga memicu peristiwa input yang menjadi bahasan utama chapter Form Events. Dua keluarga peristiwa itu berjalan bersamaan untuk aksi yang sama, dan pilihan yang tepat tergantung pertanyaan kita — peristiwa keyboard menjawab “tombol apa yang ditekan”, sedangkan input menjawab “nilai kolom sekarang apa”.
event.key vs event.code #
Dua properti pada object event keyboard sering tertukar karena keduanya mengidentifikasi tombol — tetapi dengan arti yang berbeda:
| Properti | Menunjuk | Contoh untuk huruf A | Contoh untuk Enter |
|---|---|---|---|
event.key | karakter yang dihasilkan, sesuai layout dan tombol pengubah | "a" atau "A" (dengan Shift) | "Enter" |
event.code | posisi fisik tombol pada papan ketik | "KeyA" (selalu) | "Enter" (selalu) |
event.key menjawab “karakter apa yang dimaksud pengguna” — nilainya berubah mengikuti papan ketik yang dipakai dan apakah Shift ditekan. event.code menjawab “tombol fisik mana yang ditekan” — tombol yang sama selalu punya code yang sama, apa pun layoutnya. Contoh nyata perbedaannya: pada papan ketik AZERTY yang lazim di Prancis, tombol di posisi kiri atas menghasilkan key: "a" — tetapi code-nya tetap KeyQ, mengikuti posisi fisik yang sama dengan huruf Q pada QWERTY.
Nilai key yang paling sering diperiksa antara lain: "Enter" untuk konfirmasi, "Escape" untuk menutup dialog, "Tab" untuk navigasi antar kolom, "Backspace" untuk menghapus, " " untuk spasi, serta "ArrowUp", "ArrowDown", "ArrowLeft", dan "ArrowRight" untuk navigasi arah. Semua nama mengikuti ejaan spesifikasi, bukan label yang tercetak di papan ketik. Berkas berikut mencatat keduanya sekaligus, plus mendeteksi pintasan dan penekanan berulang:
// key-vs-code.js — event.key, event.code, tombol pengubah, dan repeat
document.addEventListener("keydown", function (event) {
console.log(`key: "${event.key}" | code: ${event.code}`);
if (event.ctrlKey && event.key === "s") {
event.preventDefault();
console.log("Pintasan Ctrl+S diproses aplikasi");
}
if (event.repeat) {
console.log("(tombol ditahan, event berulang)");
}
});Simulasi kita menekan tiga kali: tombol s biasa, kombinasi Ctrl+S, lalu ArrowDown yang ditahan. Listener dipasang pada document agar setiap penekanan di mana pun terbaca.
Output yang Dihasilkan (console browser):
key: "s" | code: KeyS
key: "s" | code: KeyS
Pintasan Ctrl+S diproses aplikasi
key: "ArrowDown" | code: ArrowDown
(tombol ditahan, event berulang)Mari kita bedah:
- Baris 3 (
event.keydanevent.code): penekanansmenghasilkan key"s"(huruf kecil, tanpa Shift) dan codeKeyS. Dua penekanan pertama mencetak baris identik, tetapi hanya yang kedua memicu pintasan — bedanya ada pada tombol pengubah. - Baris 5 (
event.ctrlKey && event.key === "s"): deteksi pintasan memeriksa flagctrlKeydan karakterssecara terpisah. SaatCtrlditekan,event.keytetap"s"— huruf kecil, karena pengubah tidak ikut masuk kekey. Membandingkan dengan"Ctrl+s"adalah kesalahan yang sering terjadi. - Baris 6 (
event.preventDefault()): tanpa pembatalan ini, browser tetap menjalankan perilaku bawaanCtrl+S— memunculkan dialog simpan halaman. DenganpreventDefault(), aplikasi Siti yang mengambil alih. - Baris 10–12 (
event.repeat): tombol yang ditahan menghasilkan keydown berulang denganrepeat: true. Baris terakhir keluaran menandai penekananArrowDownyang berulang otomatis — dasar dari gerak halus pada daftar atau permainan.
Tombol Pengubah Lainnya #
Selain ctrlKey, object event keyboard menyediakan shiftKey, altKey, dan metaKey (tombol Cmd pada macOS) — semuanya boolean yang menyala saat tombol pengubah ditekan bersamaan. Kombinasi tinggal dirangkai dengan operator logika: event.shiftKey && event.key === "Tab" menangkap navigasi mundur antar kolom, dan event.metaKey && event.key === "k" memberi pengguna macOS pintasan gaya aplikasi desktop.
Perangkat masukan berikutnya yang perlu kita kuasai adalah penunjuk dalam bentuk paling umumnya: mouse, sentuhan, dan stylus. Ketiganya kini dibahas dalam satu keluarga peristiwa yang sama — topik chapter berikutnya.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
key-vs-code.js
Unduh berkas// key-vs-code.js — event.key, event.code, tombol pengubah, dan repeat
document.addEventListener("keydown", function (event) {
console.log(`key: "${event.key}" | code: ${event.code}`);
if (event.ctrlKey && event.key === "s") {
event.preventDefault();
console.log("Pintasan Ctrl+S diproses aplikasi");
}
if (event.repeat) {
console.log("(tombol ditahan, event berulang)");
}
});
papan-ketik.js
Unduh berkas// papan-ketik.js — merespons keydown dan keyup pada kolom pencarian
const kolomCari = document.querySelector("#kolom-cari");
kolomCari.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
console.log(`Cari: "${kolomCari.value}"`);
}
});
kolomCari.addEventListener("keyup", function (event) {
console.log(`keyup: "${event.key}" dilepas`);
});