How to Fix OnePageNavigation.js Uncaught TypeError in JavaScript?

Hey, I want to share a recent problem I ran into while working on a website navigation script, and how I fixed it. If you’ve ever seen this error in your JavaScript console

Error Code

Uncaught TypeError: Cannot read property 'top' of undefined

Then this post is for you. I’ll explain why this error happens, walk you through the code causing it, and show you how to fix it properly. I’ll also give some extra tips to improve your page navigation.

The Code That Causes the Error

Here’s the exact code snippet that was giving me trouble:

 OnePageNavigation = function() {
$("body").on("click", ".main-menu li a[href^='#'], .smoothscroll[href^='#'], .main-menu li a[href^='index.html'], .smoothscroll[href^='index.html'], .site-mobile-menu .site-nav-wrap li a", function(e) {
e.preventDefault();

var hash = this.hash;

$('html, body').animate({
'scrollTop': $(hash).offset().top
}, 300, 'easeInOutExpo', function(){
window.location.hash = hash;
});

});
};
OnePageNavigation();

The intention here is to create smooth scrolling behavior when clicking certain navigation links that point to anchors on the page (like #portfolio-section) or links that include an anchor in the URL (like index.html#about-section).

What the Error

Uncaught TypeError: Cannot read property 'top' of undefined

means that when JavaScript tries to access .top of $(hash).offset(), it’s getting undefined instead of an object.

Why? Because:

  • this.hash grabs the anchor part of the clicked link’s href.
  • $(hash) tries to find an element on the page with an ID matching that hash.
  • If no element exists with that ID, then $(hash).offset() returns undefined.
  • Trying to read .top of undefined causes the error.

Does It Happen Only On Some Pages

In my case:

  • On the index.html page, anchors like #portfolio-section exist, so $(hash) works fine.
  • But on portfolio.html, if the link still points to something like index.html#portfolio-section or a hash that doesn’t exist on the current page, $(hash) fails.
  • Especially on mobile view, some event handlers or menu toggles might trigger this code differently.
  • So when I click a link pointing to a non-existent anchor on the current page, the error occurs.

Check Before Accessing .offset()

The key fix is to check if the element exists before trying to scroll to it. Here’s the improved code snippet I wrote:

 OnePageNavigation = function() {
$("body").on("click", ".main-menu li a[href^='#'], .smoothscroll[href^='#'], .main-menu li a[href^='index.html'], .smoothscroll[href^='index.html'], .site-mobile-menu .site-nav-wrap li a", function(e) {
e.preventDefault();

var href = $(this).attr('href');
var isSamePageAnchor = href.startsWith('#');
var target;

if (isSamePageAnchor) {
target = $(href);
if (target.length) {
// Smooth scroll to the element
$('html, body').animate({
scrollTop: target.offset().top
}, 300, 'easeInOutExpo', function() {
window.location.hash = href;
});
} else {
// Element doesn’t exist on this page — fallback to default behavior or log warning
console.warn('Target element not found for:', href);
}
} else if (href.includes('#')) {
// Link to another page with an anchor like index.html#section
window.location.href = href;
} else {
// Regular link without anchor, just navigate
window.location.href = href;
}
});
};
OnePageNavigation();

What This Does:

  • It gets the full href of the clicked link.
  • If the href starts with #, it means the anchor is on the same page.
    • It checks if the element exists on the page.
    • If yes, smooth scroll to it.
    • If no, it shows a warning and skips scrolling.
  • If the href contains # but does not start with it, it means the link goes to another page plus an anchor.
    • It just navigates to that page normally.
  • If no # is found, it treats the link as a regular URL and navigates.

Some Extra Features I Added for Practice

While I was fixing this, I also added a couple of handy features:

Highlight the Active Menu Item on Scroll

This helps users know which section they’re currently viewing:

highlightOnScroll = function() {
$(window).on('scroll', function() {
var scrollPos = $(document).scrollTop();

$('.main-menu li a[href^="#"]').each(function() {
var currLink = $(this);
var refElement = $(currLink.attr('href'));
if (refElement.length) {
if (refElement.position().top <= scrollPos + 100 && refElement.position().top + refElement.height() > scrollPos + 100) {
$('.main-menu li a').removeClass('active');
currLink.addClass('active');
}
}
});
});
};
highlightOnScroll();

Close Mobile Menu After Clicking a Link

To improve UX on mobile devices, it’s good to automatically close the mobile menu when a user clicks any navigation link:

$("body").on("click", ".site-menu-toggle, .site-mobile-menu .site-nav-wrap li a", function() {
if ($('.site-mobile-menu').hasClass('active')) {
$('.site-mobile-menu').removeClass('active');
}
});

Add Fallback for Animation Timeout

Sometimes the scroll animation might get interrupted. To ensure the URL hash updates reliably, I added a fallback timeout:

scrollTimeout;
$('html, body').animate({scrollTop: target.offset().top}, 300, 'easeInOutExpo', function() {
window.location.hash = hash;
});
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function(){
window.location.hash = hash;
}, 350);

Final Thought

This error is very common when working with smooth scrolling and one-page navigation, especially when you mix links to different pages with anchors to sections on the same page.

The key takeaway for me was:

  • Always check if the target element exists before trying to scroll to it.
  • Handle same-page anchors differently from cross-page links.
  • Adding console warnings helps you debug missing anchors during development.
  • Extra UX touches like highlighting the current section and closing mobile menus improve usability.

I hope this helps you avoid the “Cannot read property ‘top’ of undefined” error and make your site navigation smoother and more reliable.

Related blog posts