Fix Uncrawlable Links for Better SEO
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.
What's the Problem?
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.
How to Identify This Issue
Chrome DevTools
- Open DevTools (F12) → Elements tab
- Search for
<aand manually inspect href attributes - Or run this in the Console:
document.querySelectorAll('a').forEach((a) => {
const href = a.getAttribute('href')
if (!href || href === '#' || href === '' || href.startsWith('javascript:')) {
console.log('Uncrawlable:', a.outerHTML)
}
})
Lighthouse
Run a Lighthouse SEO audit. Look for "Links are not crawlable" which lists each failing anchor element with its HTML.
The Fix
1. Always Include a Valid href
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>
2. Replace javascript:void(0)
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>.
3. Fix Framework Router Links
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.
4. Handle Dynamic Navigation
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}`)
5. Fix Anchor Placeholders
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.
6. Escape Hatch: ARIA Role
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.
Framework-Specific Solutions
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.Verify the Fix
- Run Lighthouse SEO audit again
- Confirm "Links are crawlable" shows as passing
- Use "View Page Source" (not DevTools) to see what Googlebot sees before JavaScript runs
- Check Google Search Console for crawl errors on pages that were previously unreachable
Common Mistakes
- Using anchors for buttons — If it doesn't navigate to a URL, it shouldn't be an
<a>. Use<button>for actions like modals, dropdowns, and form submissions. - Empty href with hash routing —
<a href="" @click="$router.push('/about')">still fails the audit. Use<router-link>or include the href. - Forgetting SSR rendering — In SSR apps, check that hrefs are populated during server render, not just after hydration.
- File protocol links —
file:///URLs are flagged as uncrawlable because they're not accessible to search engines. Upload files to your server and use http/https URLs.
Related Issues
Crawlable anchor issues often appear alongside:
- Link Text — Links need both valid hrefs and descriptive text
- Link Name — Accessibility also requires links to have names
- Canonical — Links should point to canonical URLs
Test Your Entire Site
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.