JavaScript mengubah dokumen statis menjadi perangkat lunak. Aplikasi satu halaman (SPA) terasa instan. Tidak ada pemuatan ulang halaman secara penuh, tidak ada layar putih yang berkedip. Namun kecepatan itu datang dengan biaya yang diabaikan oleh banyak tim: mesin dasar web mulai membusuk. Navigasi menjadi rapuh. Mesin pencari kesulitan mengikuti jalur. Pembaca layar (screen reader) menjadi bingung. Dan pengguna mendapati diri mereka terjebak dalam antarmuka yang terlihat seperti situs web tetapi berperilaku seperti aplikasi desktop yang rusak.
Pelakunya biasanya adalah sebuah div dengan handler onClick.
Berhenti Menggunakan Div sebagai Link
Sebuah div tidak memiliki makna semantik. Ia hanyalah sebuah kotak. Saat Anda memasangkan handler klik padanya dan menggunakannya untuk mengarahkan pengguna ke tampilan baru, Anda meminta browser untuk memperlakukan kotak kardus seperti sebuah pintu. Browser menolaknya. Begitu juga dengan setiap alat yang dibangun di sekitar browser.
Pembaca layar tidak mengumumkan div sebagai link atau tombol. Mereka melewatkannya, atau membacanya sebagai teks biasa. Pengguna yang menavigasi dengan suara tidak dapat menargetkannya. Crawler mesin pencari, yang memindai halaman Anda untuk URL yang dapat ditemukan, tidak melihat apa pun untuk diikuti. Rute Anda seolah-olah tidak ada.
Lebih buruk lagi, Anda kehilangan perilaku yang sudah diketahui pengguna. Link yang asli memungkinkan seseorang untuk klik kanan guna membukanya di tab baru, menandai (bookmark) tujuan, atau menyalin alamat untuk dibagikan. Pengguna keyboard berharap dapat menekan Tab untuk mencapainya dan Enter untuk membukanya. Sebuah div tidak menawarkan semua ini. Bahkan jika Anda menambahkan tabIndex, role="link", dan listener keyboard, Anda sedang membangun ulang—dengan buruk—apa yang sudah diberikan browser secara gratis. Dan Anda akan melupakan kasus ekstrem (edge case). Anda selalu begitu.
Gunakan Anchor untuk Tujuan, Button untuk Tindakan
HTML sudah menyelesaikan masalah ini. Kebingungan dimulai karena kedua elemen tersebut terlihat dapat diklik, sehingga pengembang memperlakukannya sebagai sesuatu yang dapat saling menggantikan. Padahal tidak.
Gunakan tag <a> saat Anda ingin memindahkan pengguna ke URL baru. Bukan sekadar simulasi pergantian tampilan, bukan perubahan state, melainkan lokasi yang sebenarnya. Atribut href harus berisi alamat yang nyata:
<a href="/docs">Documentation</a>
Itu saja. Jika pengguna akan pergi ke suatu tempat, gunakan link.
Gunakan <button> saat sesuatu terjadi di halaman saat ini. Tombol digunakan untuk tindakan seperti:
- Membuka modal
- Mengirimkan formulir
- Menyimpan pengaturan
- Mengubah status menu (toggle)
Link adalah untuk tujuan. Button adalah untuk tindakan. Mencampur keduanya akan membingungkan antarmuka Anda dan merusak ekspektasi pengguna.
Biarkan Browser Melakukan Tugasnya
Browser modern adalah hasil dari evolusi dan standardisasi selama puluhan tahun. Mereka menangani keamanan, riwayat (history), prefetching, dan aksesibilitas dengan lebih baik daripada JavaScript buatan Anda sendiri.
Tag anchor yang asli secara otomatis mengisi tumpukan riwayat (history stack) browser. Ia bekerja dengan menu konteks bawaan. Ia berpartisipasi dalam algoritma prefetching bawaan browser saat pengguna mengarahkan kursor (hover) atau memfokuskan elemen tersebut, membuat aplikasi Anda terasa lebih cepat tanpa Anda perlu menulis satu baris kode pun. Ia menghormati preferensi pengguna dalam membuka link. Ia bekerja sama dengan pengelola kata sandi, alat penerjemah, dan mode pembaca (reader mode).
Saat Anda menggantinya dengan fungsi navigasi JavaScript, Anda melepaskan semua manfaat tersebut. Anda tidak hanya kehilangan fitur; Anda memaksa pengguna untuk meninggalkan kebiasaan yang telah mereka bangun di setiap situs lain di internet. Itu bukan sekadar keputusan teknis. Itu adalah pengalaman pengguna yang tidak ramah.
Periksa Apa yang Sebenarnya Dirender oleh Framework Anda
React Router, Vue Router, komponen Link Next.js, SvelteKit. Alat-alat ini membuat routing sisi klien (client-side routing) terasa mudah. Namun abstraksi melahirkan kesalahan.
Periksa DOM Anda. Buka developer tools browser dan lihat elemen yang dihasilkan oleh framework Anda. Komponen <Link> harus dirender sebagai tag <a> asli dengan atribut href yang valid dalam HTML akhir. Jika ia dirender sebagai span, div, atau apa pun tanpa href yang tepat, abstraksi Anda telah gagal. Perbaiki komponennya. Timpa (override) pengaturan default. Gunakan prop passHref atau padanannya di framework tersebut. Jangan percaya begitu saja bahwa framework akan melakukannya dengan benar tanpa verifikasi.
Hal ini juga penting untuk masalah ketidakcocokan hidrasi (hydration mismatches). Jika server merender link dan klien melakukan hidrasi menjadi non-link, Anda menciptakan bug aksesibilitas yang sulit dilacak karena HTML terlihat benar di kode sumber Anda tetapi salah di DOM yang sedang berjalan.
Larang Tujuan Palsu
Ada sebuah pola yang sulit mati: href="javascript:void(0)". Pengembang menggunakannya saat mereka menginginkan sesuatu yang terlihat seperti link tetapi berperilaku seperti tombol, biasanya karena mereka tidak ingin mengatur gaya (styling) tombol atau karena basis kode lama menuntut hal tersebut.
Stop. This is not a URL. It gives the browser no destination. It pollutes the history stack with unusable states. It breaks browser history and accessibility. It is a trap. If you need click behavior without navigation, you need a <button>. Style it to look however you want. CSS does not care whether the element is a button or a link. Your users do.
Write Text That Explains Where the User Is Going
The words inside your link matter. Screen reader users often pull up a list of every link on the page to scan quickly. If your links all say "Read more" or "Click here," that list becomes useless noise.
Be specific. Compare these:
- Bad:
<a href="/security/api-guide">Read more</a> - Good:
<a href="/security/api-guide">Read the API security guide</a>
The second tells the user exactly what they will find. It gives search engines context about the destination page. It makes your link list navigable. Descriptive link text is one of the cheapest accessibility wins you can earn.
Test Like You Mean It
Architecture means nothing if you do not verify it.
First, test your keyboard flow. Unplug your mouse. Tab through every interactive element on your site. Every genuine link must show a visible focus outline, not a subtle glow that disappears against your background, but a clear ring that a tired eye can spot. Press Enter. It must activate the link. If Tab skips an element, or if Enter does nothing, you have a bug.
Second, test your routes at the server level. Client-side routing is a thin veneer. If a user bookmarks /dashboard/reports and returns tomorrow, or hits refresh, your server must know how to serve that page. Configure your reverse proxy or your server framework to fall back to your application shell for unknown paths, or serve the correct HTML directly. A dead 404 on refresh is not a minor bug. It is a broken promise.
JavaScript is a powerful layer
