Skip to content

feat(#1932): implement smooth scrolling for anchor navigation across site #1965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: gh-pages
Choose a base branch
from

Conversation

Mohit5Upadhyay
Copy link

Description

This PR implements smooth scrolling for in-page navigation across the Express.js website as mentioned in Issue : #1932

This improves the user experience by ensuring that navigation to sections via anchor links transitions smoothly, rather than jumping abruptly.

Closes #1932

Video

smooth-scrolling.mp4

@Mohit5Upadhyay Mohit5Upadhyay requested a review from a team as a code owner July 7, 2025 10:55
Copy link

netlify bot commented Jul 7, 2025

Deploy Preview for expressjscom-preview ready!

Name Link
🔨 Latest commit 736831c
🔍 Latest deploy log https://app.netlify.com/projects/expressjscom-preview/deploys/687284c4ba7dd4000809c1fc
😎 Deploy Preview https://deploy-preview-1965--expressjscom-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

js/app.js Outdated
$(document).on('click', 'a[href^="#"]:not([href="#"]):not([href="#top"])', function(e) {
var href = $(this).attr('href');
if (smoothScrollToElement(href)) {
e.preventDefault();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please remove this line https://github.com/expressjs/expressjs.com/blob/gh-pages/js/menu.js#L186 ? Since default behavior stopped here.

js/app.js Outdated
// top link
$('#top').click(function(e){
$('html, body').animate({scrollTop : 0}, 500);
return false;
});

// Smooth scrolling for all anchor links
$(document).on('click', 'a[href^="#"]:not([href="#"]):not([href="#top"])', function(e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$(document).on('click', 'a[href^="#"]:not([href="#"]):not([href="#top"])', function(e) {
$("#api-doc").on('click', 'a[href^="#"]:not([href="#"]):not([href="#top"])', function(e) {

We should minimize the scope of this click event. Currently, $(document).on('click'...) attaches the handler to all anchor links with # across every page. However, smooth scrolling is only needed on API pages, since the TOC exists only there. Scoping it to #api-doc avoids unnecessary event handling and prevents inconsistent anchor # behavior on other pages. Also, checking "#api-doc" exist on page is required before applying click event.

Copy link
Member

@bjohansebas bjohansebas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

As i mentioned in the issue, this can be handled through CSS, javascript is not necessary.

@ShubhamOulkar
Copy link
Member

this can be handled through CSS,

I am OK with CSS only solution. But this approach comes with some limitations, like we cannot control scroll behavior and can not add header offsets. But it is fine if headings are not hiding behind the header bar on anchor link click.

@Mohit5Upadhyay
Copy link
Author

Thanks @bjohansebas for the suggestion about a CSS-only solution!
Unfortunately, I think for this project, CSS alone isn’t sufficient because:

  • IDs like #app.METHOD (http://localhost:4000/en/5x/api.html#app.listen) contain dots, which CSS can’t reliably scroll to without custom JS.
  • We need a precise scroll offset (120px) to avoid headings hiding behind the navbar.

So I’d propose keeping the JS smooth scroll, scoped only to #api-doc to avoid global impact as per suggested by @ShubhamOulkar.

Let me know if you’d prefer another approach!
Thanks again for your feedback.

@bjohansebas
Copy link
Member

But it is fine if headings are not hiding behind the header bar on anchor link click.

The headings are never hidden by the header bar, or at least I’ve been trying to reproduce it and haven’t been able to.

IDs like #app.METHOD (http://localhost:4000/en/5x/api.html#app.listen) contain dots, which CSS can’t reliably scroll to without custom JS.

That doesn’t matter in CSS, since the effect will be applied to all elements anyway.

* {
  scroll-behavior: smooth;
}

@Mohit5Upadhyay
Copy link
Author

Hi @bjohansebas and @ShubhamOulkar,

I’ve updated the implementation to follow your suggestion of a CSS-only smooth scrolling solution.

  • I removed all the custom JavaScript smooth scroll code I previously added.
  • Instead, I’ve applied this in CSS:
* {
  scroll-behavior: smooth;
}

h1, h2, h3, h4, h5, h6,
[id] {
  scroll-margin-top: 120px;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

Let me know if you’d like any further changes!
Thanks for your time! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Implement Smooth Scrolling
3 participants