Skip to content

Conversation

@malav2110
Copy link
Contributor

@malav2110 malav2110 commented Jan 6, 2026

Description

This PR adds functionality to preserve sidebar scroll location on Learn Page

Validation

Before:
https://github.com/user-attachments/assets/41ca31eb-72c2-447a-a6a7-2d451171775e

After:
https://github.com/user-attachments/assets/656713ee-5d03-430f-beda-8ae491f415a8

Related Issues

Fixes #8336

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run pnpm format to ensure the code follows the style guide.
  • I have run pnpm test to check if all tests are passing.
  • I have run pnpm build to check if the website builds without errors.
  • I've covered new added functionality with unit tests if necessary.

Copilot AI review requested due to automatic review settings January 6, 2026 01:41
@malav2110 malav2110 requested a review from a team as a code owner January 6, 2026 01:41
@vercel
Copy link

vercel bot commented Jan 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
nodejs-org Ready Ready Preview Jan 7, 2026 6:43am

@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

👋 Codeowner Review Request

The following codeowners have been identified for the changed files:

Team reviewers: @nodejs/nodejs-website

Please review the changes when you have a chance. Thank you! 🙏

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements scroll position preservation for the sidebar on the Learn Page, addressing issue #8336 where the sidebar would reset to the top when navigating between articles. The implementation uses React's forwardRef pattern and a custom hook to track and restore scroll positions across navigation.

Key Changes:

  • Created a new useNavigationState hook that debounces scroll events and stores scroll positions in a context-based state store
  • Modified the Sidebar component to support ref forwarding, allowing parent components to access the underlying DOM element
  • Integrated the scroll preservation functionality into the withSidebar component

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
packages/ui-components/src/Containers/Sidebar/index.tsx Converted from functional component to forwardRef to expose the sidebar element for scroll position tracking
apps/site/hooks/client/useNavigationState.ts New custom hook that manages scroll position state using context, debouncing, and DOM manipulation
apps/site/hooks/client/index.ts Added export for the new useNavigationState hook
apps/site/components/withSidebar.tsx Integrated scroll position preservation by using useNavigationState hook with a ref to the sidebar element

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…and fixed potential memory leak issue in useNavigationState
import type { RefObject } from 'react';

const useNavigationState = <T extends HTMLElement>(
id: string,
Copy link
Member

Choose a reason for hiding this comment

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

Do you need the ID if you have the ref or is the id used for something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do need id as multiple components might use this hook with different elements and the scroll positions are stored in the shared context object keyed by id.

}, [id, ref, navigationState, debounceTime]);

useEffect(() => {
const element = ref.current;
Copy link
Member

Choose a reason for hiding this comment

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

Let's remove the redundant variable assignment. Let's use direct reference. I don't see why doing the assignment is necessary

debounceTime = 300
) => {
const navigationState = useContext(NavigationStateContext);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
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
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const timeoutRef = useRef<NodeJS.Timeout>();

No need to have duality of null. By default a useRef .current will be undefined, so no need for explicit null value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TS overloads for useRef get a bit noisy without an explicit initial value, so I’m switching this to NodeJS.Timeout | undefined and initializing with undefined instead of null.

Copy link
Member

@ovflowd ovflowd left a comment

Choose a reason for hiding this comment

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

I feel we're missing tests that verify the hook works as expected and scrolls to an element that was outside of the view.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

Lighthouse Results

URL Performance Accessibility Best Practices SEO Report
/en 🟢 98 🟢 96 🟢 100 🟢 100 🔗
/en/about 🟢 100 🟢 97 🟢 100 🟠 88 🔗
/en/about/previous-releases 🟢 98 🟢 100 🟢 100 🟢 100 🔗
/en/download 🟢 97 🟢 100 🟢 100 🟢 100 🔗
/en/download/archive/current 🟢 100 🟢 100 🟢 100 🟢 100 🔗
/en/blog 🟢 99 🟢 100 🟢 96 🟢 100 🔗

@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

❌ Patch coverage is 21.42857% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.37%. Comparing base (8c5a7dd) to head (ece53b4).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/site/hooks/client/useNavigationState.ts 20.00% 44 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8517      +/-   ##
==========================================
- Coverage   74.70%   74.37%   -0.34%     
==========================================
  Files         102      103       +1     
  Lines        8956     9012      +56     
  Branches      305      306       +1     
==========================================
+ Hits         6691     6703      +12     
- Misses       2263     2307      +44     
  Partials        2        2              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

…r component and add scroll handling functionality
}, [id, ref]);

// Save scroll position on scroll
const handleScroll = useCallback(
Copy link
Member

Choose a reason for hiding this comment

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

nit: not sure if this needs to be a callback

if (savedState && savedState.y !== element.scrollTop) {
element.scroll({ top: savedState.y, behavior: 'auto' });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
Copy link
Member

Choose a reason for hiding this comment

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

nit: add a comment explaining why only id and ref changes are enough.

export { default as useDetectOS } from './useDetectOS';
export { default as useMediaQuery } from './useMediaQuery';
export { default as useClientContext } from './useClientContext';
export { default as useScrollToElement } from './useScrollToElement';
Copy link
Member

@ovflowd ovflowd Jan 7, 2026

Choose a reason for hiding this comment

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

You also gotta make stub exports on hooks/server that when called throw exceptions. (see examples on hooks/server folder)

Copy link
Member

@ovflowd ovflowd left a comment

Choose a reason for hiding this comment

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

Left a few nits, but SGTM! And thanks for the work and effort here 🙇

Copy link
Member

@avivkeller avivkeller left a comment

Choose a reason for hiding this comment

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

Can you pnpm version patch in packages/ui-components?

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.

Selected article in sidebar doesn’t scroll into view

3 participants