Search engines discover your pages by following links. When your anchor elements don't have proper href attributes, Googlebot can't crawl them—and those pages won't get indexed.
Modern JavaScript frameworks make it easy to handle clicks without real links. But if there's no valid href, search engines see a dead end.
Lighthouse flags these patterns as uncrawlable:
Empty or missing href:
<a onclick="navigate('/about')">About</a>
<a href="">About</a>
<a href="#">About</a>
JavaScript pseudo-URLs:
<a href="javascript:void(0)">About</a>
<a href="javascript:">About</a>
Invalid URLs:
<a href="file:///path/to/file">Download</a>
Click handlers without href:
<a @click="goToAbout">About</a>
Googlebot does execute JavaScript, but it doesn't click on elements. It follows href attributes. No href, no crawl.
<a and manually inspect href attributesdocument.querySelectorAll('a').forEach((a) => {
const href = a.getAttribute('href')
if (!href || href === '#' || href === '' || href.startsWith('javascript:')) {
console.log('Uncrawlable:', a.outerHTML)
}
})
Run a Lighthouse SEO audit. Look for "Links are not crawlable" which lists each failing anchor element with its HTML.
Every navigation link needs a real URL in the href attribute.
<!-- Before -->
<a onclick="navigate('/about')">About</a>
<!-- After -->
<a href="/about">About</a>
If you need JavaScript behavior, use the href as the fallback:
<a href="/about" onclick="handleClick(event)">About</a>
This pattern was common before we had better alternatives. Replace it with a real URL.
<!-- Before -->
<a href="javascript:void(0)" onclick="showModal()">Open Modal</a>
<!-- After: if it's a true navigation -->
<a href="/modal-content">Open Modal</a>
<!-- Or: if it's an action, use a button -->
<button type="button" onclick="showModal()">Open Modal</button>
Rule of thumb: If clicking takes you to a new page, use <a> with an href. If it triggers an action on the current page, use <button>.
Framework routers should handle this automatically, but verify your implementation:
<!-- Vue Router -->
<router-link to="/about">About</router-link>
<!-- Renders: <a href="/about">About</a> ✓ -->
<!-- React Router -->
<Link to="/about">About</Link>
<!-- Renders: <a href="/about">About</a> ✓ -->
If you're using custom click handlers instead of router components, switch to the proper router link component.
When URLs are generated dynamically, ensure the href is populated at render time—not just on click.
<!-- Before: href is empty until clicked -->
<a href="" @click="href = getProductUrl()">View Product</a>
<!-- After: href is set during render -->
<a :href="productUrl">View Product</a>
// Compute the URL upfront
const productUrl = computed(() => `/products/${product.id}`)
If you're using <a> without href as a placeholder or for styling, reconsider.
<!-- Before: anchor as placeholder -->
<a class="nav-item disabled">Coming Soon</a>
<!-- After: use span for non-links -->
<span class="nav-item disabled">Coming Soon</span>
The only valid case for <a> without href is as a named anchor: <a id="section-1"></a>. Even then, prefer id on any element.
If you must use an anchor without href for technical reasons, add role to exclude it from the audit:
<a role="button" onclick="showMenu()">Menu</a>
But this is a band-aid. Prefer a real <button> element.
Link component from next/link, never raw anchors with click handlers. The Link component renders a proper <a> with href for crawlers.NuxtLink for all internal navigation. It handles both client-side routing and proper href rendering. Avoid @click navigation on raw anchors.<a>. Use <button> for actions like modals, dropdowns, and form submissions.<a href="" @click="$router.push('/about')"> still fails the audit. Use <router-link> or include the href.file:/// URLs are flagged as uncrawlable because they're not accessible to search engines. Upload files to your server and use http/https URLs.Crawlable anchor issues often appear alongside:
Uncrawlable links often hide in navigation components, footers, or dynamically loaded sections. Unlighthouse scans your entire site and identifies every page with uncrawlable anchors, so you can fix them all at once.