Broken hash links (also known as anchor links or fragment identifiers) can create a frustrating user experience when visitors try to navigate to specific sections of your content. Ensuring these links work properly is crucial for smooth on-page navigation.
Hash links are URLs that contain a '#' symbol followed by an identifier that should correspond to an element's ID on the page. They break when the target ID doesn't exist:
1 2 3 4 5 6 7 8 9 10
<!-- Broken Hash Link --> <a href="#section1">Jump to Section 1</a> <!-- But #section1 doesn't exist in the document --> <!-- Working Hash Link --> <a href="#section2">Jump to Section 2</a> <section id="section2"> <h2>Section 2</h2> <p>Content here...</p> </section>
Broken hash links affect your website in several ways:
User Experience Impact
Accessibility Issues
Technical Consequences
First, identify broken hash links:
1 2 3 4 5 6 7 8 9
// Function to find broken hash links function findBrokenHashLinks() { const hashLinks = document.querySelectorAll('a[href^="#"]'); return Array.from(hashLinks).filter(link => { const hash = link.getAttribute('href').slice(1); return hash && !document.getElementById(hash); }); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<!-- Before: Broken Implementation --> <nav class="table-of-contents"> <a href="#intro">Introduction</a> <a href="#section1">Section 1</a> <a href="#conclusion">Conclusion</a> </nav> <div> <!-- Missing IDs! --> <h2>Introduction</h2> <h2>Section 1</h2> <h2>Conclusion</h2> </div> <!-- After: Working Implementation --> <nav class="table-of-contents"> <a href="#intro">Introduction</a> <a href="#section1">Section 1</a> <a href="#conclusion">Conclusion</a> </nav> <div> <h2 id="intro">Introduction</h2> <h2 id="section1">Section 1</h2> <h2 id="conclusion">Conclusion</h2> </div>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
function ScrollLink({ targetId, children }) { useEffect(() => { // Verify target exists if (!document.getElementById(targetId)) { console.warn(`Missing target element: #${targetId}`); } }, [targetId]); const handleClick = (e) => { e.preventDefault(); const element = document.getElementById(targetId); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; return ( <a href={`#${targetId}`} onClick={handleClick}> {children} </a> ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
<template> <a :href="'#' + targetId" @click.prevent="scrollToTarget" :class="{ 'broken': !targetExists }" > <slot></slot> </a> </template> <script> export default { props: { targetId: String }, data() { return { targetExists: false } }, mounted() { this.checkTarget(); }, methods: { checkTarget() { this.targetExists = !!document.getElementById(this.targetId); if (!this.targetExists) { console.warn(`Missing target element: #${this.targetId}`); } }, scrollToTarget() { const element = document.getElementById(this.targetId); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } } </script>
Implementation Guidelines
Accessibility Rules
Quality Control
Indexguru's SEO Analyzer
Development Tools
Testing Tools
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<nav class="toc"> <h2>Contents</h2> <ul> <li><a href="#introduction">Introduction</a></li> <li><a href="#methods">Methods</a></li> <li><a href="#results">Results</a></li> <li><a href="#conclusion">Conclusion</a></li> </ul> </nav> <article> <h2 id="introduction">Introduction</h2> <h2 id="methods">Methods</h2> <h2 id="results">Results</h2> <h2 id="conclusion">Conclusion</h2> </article>
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<div class="faq"> <nav class="faq-nav"> <a href="#q1">Question 1</a> <a href="#q2">Question 2</a> </nav> <div class="faq-content"> <h3 id="q1">Question 1</h3> <p>Answer 1...</p> <h3 id="q2">Question 2</h3> <p>Answer 2...</p> </div> </div>
1 2 3 4 5 6 7
<a href="#main-content" class="skip-link"> Skip to main content </a> <main id="main-content"> <!-- Main content --> </main>
Proper hash link implementation leads to:
1 2 3 4 5 6 7
<!-- Bad --> <a href="#Section1">Link</a> <h2 id="section1">Section 1</h2> <!-- Good --> <a href="#section1">Link</a> <h2 id="section1">Section 1</h2>
1 2 3 4 5 6 7
<!-- Bad --> <a href="#user's-section">Link</a> <h2 id="user's-section">Section</h2> <!-- Good --> <a href="#user-section">Link</a> <h2 id="user-section">Section</h2>
1 2 3 4 5 6 7 8 9
<!-- Bad --> <a href="#dynamic-section">Link</a> <!-- Section loaded later --> <!-- Good --> <a href="#dynamic-section">Link</a> <div id="dynamic-section"> <!-- Content loaded here --> </div>
While hash links might seem like a simple feature, their proper implementation is crucial for smooth on-page navigation and user experience. By following these guidelines and regularly testing your hash links, you can create a more user-friendly website.
Need help monitoring your website's hash links? Try Indexguru's SEO tools to automatically detect broken hash links and get actionable recommendations for improvement.
Takes 5 minutes to setup