
Element Code: PE-020
<a> tags with a real URL in the href attribute. Navigation built with onclick handlers, divs, buttons, or javascript:void(0) is invisible for link discovery, passes no link equity, and quietly orphans the pages behind it. Put a crawlable href on everything that navigates.What counts as a JavaScript link
A JavaScript link is any clickable element that navigates the user through script instead of through a standard anchor. The usual shapes: a <div> or <span> with an onclick handler that sets window.location, a <button> wired to a router, an anchor with href="#" or href="javascript:void(0)" where the real destination lives only in the click handler, or a menu component that builds its navigation entirely in event listeners.
To a human with a mouse, these work perfectly. That is exactly why they survive code review. To a crawler, they mostly do not exist, and Google is unambiguous about this: its JavaScript SEO documentation states that Google can follow links only if they are <a> tags with an href attribute. Googlebot does not click things. It renders the page, extracts URLs from anchor hrefs, and moves on. A destination that only materializes when an event handler fires is a destination Googlebot never learns about from that page.
Why this hits harder than most technical issues
Most technical SEO problems degrade something. This one deletes something. Three separate losses stack up:
Discovery. If the only paths to your product detail pages run through a JavaScript-driven filter or a scripted menu, those pages are orphans in Google's link graph. They might still get found through the XML sitemap, but sitemap-only URLs crawl slower, and a page with zero internal links pointing at it starts life with a credibility problem.
Link equity. PageRank flows through anchors. A div with a click handler passes nothing. I have watched a retailer rebuild its category navigation as a scripted mega-menu and wondered why deep categories bled positions over the following weeks: the pages were still in the sitemap, still indexed, but the internal links that had been feeding them authority had effectively vanished. The damn pages looked linked to every human who checked.
Anchor text. Even when a page gets discovered another way, the descriptive anchor text that tells Google what the target is about never gets attributed. "Waterproof hiking boots" as anchor text is a relevance signal you are throwing away.
And beyond SEO: script-only navigation usually breaks middle-click to open in a new tab, breaks keyboard navigation and screen readers, and breaks the browser's link preview. The accessibility failure and the crawlability failure are the same failure.
Which patterns are crawlable
Pattern reference
| Pattern | Googlebot follows it? | Verdict |
|---|---|---|
<a href="/page/"> | Yes | The standard. Use it. |
<a href="/page/" onclick="..."> | Yes | Fine. JS enhances, href remains the source of truth. |
| SPA router link rendering a real href | Yes | React Router Link, Next.js Link, Vue router-link all output proper anchors. Verify in rendered HTML. |
<a href="#"> + handler | No (follows to #, i.e. nowhere) | Replace the # with the real destination. |
<a href="javascript:void(0)"> | No | Google explicitly warns against javascript: URLs in links. |
<div onclick="location.href=..."> | No | Invisible as a link. Rebuild as an anchor. |
<button> that routes | No | Buttons are for actions (submit, toggle). Navigation gets an anchor. |
How to detect it on your site
- Compare a raw crawl to a rendered crawl. In Screaming Frog, crawl once with plain HTML extraction, then again with JavaScript rendering enabled (Config, Spider, Rendering). Now compare inlinks per URL. Pages with healthy inlink counts in neither crawl, but which you know your menus "link" to, are your victims. Sitebulb runs the same comparison and visualizes the delta nicely.
- Disable JavaScript and click around. Toggle JS off in DevTools (Command palette, "Disable JavaScript") and try to use your main nav, faceted filters, pagination, and footer. Anything that stops being a followable link deserves scrutiny. This five-minute test finds most offenders.
- Inspect the rendered HTML in Search Console. URL Inspection, Test Live URL, View Tested Page. Search the rendered source for the hrefs you expect. If your category page's product links are not in that HTML as anchors, Google is not seeing them either.
- Grep the codebase. Searching templates for
javascript:void,href="#", andonclicknear navigation components is crude and effective. - Watch server logs. Sections of the site Googlebot rarely requests, despite being "linked" from high-traffic templates, are a symptom worth chasing back to the markup.
How to fix it
- Give every navigation element a real anchor. The destination URL goes in the href. If you want client-side routing on top, attach the handler to the anchor and call preventDefault; crawlers read the href, users get the SPA experience. This is standard progressive enhancement and every major framework supports it out of the box.
- Use your framework's link component, not raw handlers. Next.js Link, React Router Link, Nuxt's NuxtLink all render anchors with hrefs. The bugs appear when developers bypass them with onClick navigation on divs and buttons.
- Make filter and pagination states real URLs where you want them indexed. A "load more" button can stay a button if a crawlable paginated alternative exists in the markup.
- Keep buttons for actions. Add to cart, open modal, toggle menu: buttons. Go to another URL: anchor. This split also fixes your accessibility story for free.
- Re-crawl after the fix. Rendered Screaming Frog crawl, confirm the target pages now show inlinks with sensible anchor text, then watch crawl stats pick up over the following weeks.
What good looks like: every URL you care about is reachable through anchor hrefs present in the rendered HTML, no javascript: or bare # hrefs anywhere in navigation, and your raw versus rendered crawls tell approximately the same link story.
- Put the real destination URL in every anchor's href
- Layer JS behavior on top of working anchors (preventDefault pattern)
- Use framework link components that render true anchors
- Verify links exist in the rendered HTML, not just in the browser
- Audit nav, filters, and pagination after every front-end redesign
- Navigate with divs, spans, or buttons plus click handlers
- Ship
href="#"orjavascript:void(0)in navigation - Assume the sitemap compensates for missing internal links
- Trust that "it works when I click it" means crawlers see it
- Hide your only path to deep pages inside scripted mega-menus
FAQ
Google renders JavaScript now. Doesn't that make this a non-issue?
My pages are indexed anyway via the sitemap. Why should I care?
Is onclick on an anchor with a real href okay?
What about links that appear only after user interaction, like an accordion or a tab?
Do JavaScript links at least pass PageRank if Google finds the URL some other way?
An advanced audit compares your raw and rendered link graphs, finds the pages your navigation silently abandoned, and hands your developers an exact fix list.
Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.
About SEO ProCheck
Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.
Work With Me
Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.
Subscribe to our newsletter!
Recent Posts
- Can AI Crawlers Actually Read Your Site? I Measured 400 of the Biggest September 5, 2026
- The Pre-Publish Quality Gate for AI-Assisted Content August 6, 2026
- AGENTS.md vs llms.txt vs llms-full.txt: Which Agent File Does What July 18, 2026







