JavaScript turned static documents into software. Single-page apps feel instant. No full page reloads, no flickering white screens. But that speed comes with a cost that many teams ignore: the basic machinery of the web starts to rot. Navigation becomes brittle. Search engines struggle to follow paths. Screen readers get lost. And users find themselves trapped in interfaces that look like websites but behave like broken desktop applications.

The culprit is usually a div with an onClick handler.

A div carries no semantic meaning. It is a box. When you strap a click handler onto it and use it to route users to a new view, you are asking the browser to treat a cardboard box like a door. The browser refuses. So does every tool built around the browser.

Screen readers do not announce a div as a link or a button. They skip over it, or they read it as plain text. A user navigating by voice cannot target it. A search engine crawler, scanning your page for discoverable URLs, sees nothing to follow. Your route might as well not exist.

Worse, you lose the behaviors users already know. A real link lets someone right-click to open in a new tab, bookmark the destination, or copy the address to share. Keyboard users expect to hit Tab to reach it and Enter to open it. A div offers none of this. Even if you bolt on tabIndex and role="link" and keyboard listeners, you are rebuilding, poorly, what the browser gives you for free. And you will forget an edge case. You always do.

Use Anchors for Destinations, Buttons for Actions

HTML already solved this. The confusion starts because both elements look clickable, so developers treat them as interchangeable. They are not.

Use an <a> tag when you want to move the user to a new URL. Not a simulated view swap, not a state change, but an actual location. The href attribute should contain a real address:

<a href="/docs">Documentation</a>

That is it. If the user is going somewhere, use a link.

Use a <button> when something happens on the current page. Buttons are for actions such as:

  • Opening a modal
  • Submitting a form
  • Saving settings
  • Toggling a menu

Links are for destinations. Buttons are for actions. Mixing the two muddles your interface and breaks user expectations.

Let the Browser Do Its Job

Modern browsers are the result of decades of evolution and standardization. They handle security, history, prefetching, and accessibility better than your hand-rolled JavaScript ever will.

A genuine anchor tag automatically feeds the browser history stack. It works with the native context menu. It participates in the browser's built-in prefetching algorithms when the user hovers or focuses it, making your app feel faster without you writing a line of code. It respects the user's preferences for opening links. It cooperates with password managers, with translation tools, with reader modes.

When you replace that with a JavaScript navigation function, you opt out of all of it. You are not just losing features; you are forcing users to abandon habits they have built across every other site on the internet. That is not a technical decision. It is a hostile user experience.

Check What Your Framework Actually Renders

React Router, Vue Router, Next.js Link components, SvelteKit. These tools make client-side routing feel effortless. But abstraction breeds mistakes.

Inspect your DOM. Open the browser's developer tools and look at the elements your framework emits. A <Link> component should render as a real <a> tag with a valid href attribute in the final HTML. If it renders as a span, a div, or anything else without a proper href, your abstraction has failed you. Fix the component. Override the default. Use the passHref prop or the framework equivalent. Do not trust the framework to get it right without verification.

This matters for hydration mismatches too. If the server renders a link and the client hydrates it into a non-link, you create accessibility bugs that are hard to trace because the HTML looks correct in your source code but wrong in the live DOM.

Ban Fake Destinations

There is a pattern that refuses to die: href="javascript:void(0)". Developers use it when they want something that looks like a link but acts like a button, usually because they do not want to style a button or because an older codebase demands it.

Stopp. Das ist keine URL. Sie gibt dem Browser kein Ziel vor. Sie verschmutzt den History-Stack mit unbrauchbaren Zuständen. Sie bricht den Browserverlauf und die Barrierefreiheit. Es ist eine Falle. Wenn Sie Klick-Verhalten ohne Navigation benötigen, brauchen Sie ein <button>. Gestalten Sie es so, wie Sie möchten. CSS ist es egal, ob das Element ein Button oder ein Link ist. Ihre Nutzer hingegen schon.

Schreiben Sie Texte, die erklären, wohin der Nutzer gelangt

Die Wörter innerhalb Ihres Links sind entscheidend. Nutzer von Screenreadern rufen oft eine Liste aller Links auf der Seite auf, um diese schnell zu scannen. Wenn Ihre Links alle „Mehr lesen“ oder „Hier klicken“ heißen, wird diese Liste zu nutzlosem Rauschen.

Seien Sie spezifisch. Vergleichen Sie dies:

  • Schlecht: <a href="/security/api-guide">Mehr lesen</a>
  • Gut: <a href="/security/api-guide">Lesen Sie den API-Sicherheitsleitfaden</a>

Der zweite zeigt dem Nutzer genau, was er finden wird. Er gibt Suchmaschinen Kontext über die Zielseite. Er macht Ihre Linkliste navigierbar. Beschreibender Linktext ist einer der einfachsten und kostengünstigsten Wege, die Barrierefreiheit zu verbessern.

Testen Sie mit vollem Einsatz

Architektur bedeutet nichts, wenn Sie sie nicht verifizieren.

Erstens: Testen Sie Ihren Tastatur-Flow. Ziehen Sie Ihre Maus ab. Tabben Sie sich durch jedes interaktive Element auf Ihrer Website. Jeder echte Link muss eine sichtbare Fokus-Kontur anzeigen – keinen dezenten Schimmer, der vor Ihrem Hintergrund verschwindet, sondern einen klaren Ring, den auch ein müdes Auge erkennt. Drücken Sie Enter. Der Link muss aktiviert werden. Wenn Tab ein Element überspringt oder Enter nichts bewirkt, haben Sie einen Bug.

Zweitens: Testen Sie Ihre Routen auf Server-Ebene. Clientseitiges Routing ist nur eine dünne Schicht. Wenn ein Nutzer /dashboard/reports als Lesezeichen setzt und morgen zurückkehrt oder die Seite aktualisiert, muss Ihr Server wissen, wie er diese Seite ausliefert. Konfigurieren Sie Ihren Reverse Proxy oder Ihr Server-Framework so, dass es bei unbekannten Pfaden auf Ihren Application Shell zurückgreift oder direkt das korrekte HTML ausliefert. Ein toter 404-Fehler beim Aktualisieren ist kein kleiner Bug. Es ist ein gebrochenes Versprechen.

JavaScript ist eine leistungsstarke Ebene