Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

interactionsRAMS

An Anchor Without href Is Not a Link

NEVER

NEVER: Render an `<a>` without `href` and drive it from `onClick` alone. `href` is what MAKES it a link: without it the browser exposes the element as `generic` — no link role, not focusable, not in the tab order, absent from the screen reader's links list, and mouse-only. Two branches: if it NAVIGATES, give it a real `href` (you get focus, the link role, Enter, middle-click, Cmd-click, "Copy link address" for free); if it performs an ACTION, it was never a link — use `<button>`.

An <a> with only an onClick has no link role, no focus, and no place in the tab order

// no: role-less, unfocusable, mouse-only
<a onClick={() => navigate("/profile")}>View profile</a>
// yes
<a href="/profile">View profile</a>

Bad

Good

Why it matters

Rams files this Critical, and the reason is that it does not look like a bug. `<a onClick={() => navigate("/profile")}>View profile</a>` reads as correct semantic HTML and passes a naive "did you use the right element?" check — you did reach for the native element. But `href` is not decoration; it is what makes the element a link. Without it the browser exposes an `<a>` as a `generic`: no link role, not focusable, not in the tab order, and absent from the screen reader's list of links, so a keyboard user tabs straight past it and a screen-reader user never learns it exists.

It is mouse-only, and it is extremely common in React. Note this is the INVERSE of three principles already in this corpus, not a duplicate of any of them: `interactions-rams-semantic-handlers` covers a non-interactive element pretending to be interactive (`<div onClick>`), `content-semantics-first` says do not reach for `role="button"` when a button exists, and `interactions-rams-keyboard-handlers` covers onClick with no onKeyDown.

Here you reached for the native element, and it still fails. The fix depends on intent, and there are exactly two branches. If it navigates, give it a real `href` — the browser then hands you focus, the link role, Enter activation, middle-click and Cmd-click to open in a new tab, and "Copy link address", none of which an onClick handler can synthesise. If it performs an action, it was never a link: use `<button>`.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.