sfw/fix
Broken #anchor low

Broken Anchor / Jump Link (Missing Fragment ID)

A same-page #jump link points at an element id that doesn't exist, so the click goes nowhere.

What you see

Clicking "Jump to Pricing" → URL becomes example.com/plans#pricing
but the page does not scroll. No element with id="pricing" exists.

What’s actually happening

You click a table-of-contents or "back to top" link and the page doesn't move, or it snaps to the top instead of the target. The address bar still picks up the #fragment, but there's no element with that id to scroll to. It tends to surface after a heading gets reworded or a section is pulled, leaving the link pointing at an id that's gone. Harmless to rendering, but it breaks navigation and quietly erodes trust in long docs.

Common causes

  • The target id was renamed or deleted when a heading was edited (auto-generated heading IDs shift when the text changes)
  • A typo or case mismatch between href="#Pricing" and id="pricing" — fragment matching is case-sensitive
  • A stale table of contents still lists a section that was removed
  • A CMS or Markdown renderer changed its slug algorithm, so old #our-pricing no longer matches a regenerated id
  • The id lives on an element that's removed or not yet rendered (lazy-loaded tab/accordion) when the jump fires

How to fix it

  1. Confirm the mismatchIn DevTools console run document.getElementById('pricing'). null means the target is missing — that's why the jump dies. Compare the href fragment against the actual id character for character.
  2. Add or correct the matching idEither restore id="pricing" on the destination element or update the link to the id that exists now. Both sides must match exactly, including case.
  3. Pin IDs on headings you link toDon't rely on auto-generated slugs that move when copy changes. Set an explicit, stable id on any heading that's a jump target so future edits don't break the anchor.
  4. Handle lazy-rendered targetsIf the section loads on demand (tab/accordion), open or mount it first, then scroll — element.scrollIntoView() after the content renders, since a fragment can't reach a node that isn't in the DOM yet.

Stop it recurring

Add a link-check step that resolves in-page #fragments against rendered IDs and fails the build on a miss.

Related errors