feat: persist sidebar scroll position across page navigations #74
Description
Problem
The sidebar navigation currently resets to the top every time the user navigates between pages.
For readers working through content in sections deep in the sidebar (e.g. Node-API, Diagnostics,
or Asynchronous Work), this means manually scrolling back down after every page visit — which creates
a frustrating and disorienting experience.
Additionally, SideBar from @node-core/ui-components does not support forwardRef, so passing
ref={sidebarRef} to it is silently ignored. This means the scroll restoration logic in
useScrollToElement and useScroll never receives a valid DOM reference to attach the scroll listener to.
Proposed Solution
-
Fix ref acquisition – Use
useLayoutEffectinSidebar/index.jsxto manually assignsidebarRef.current
to the rendered<aside>element beforeuseEffects run, ensuring the scroll listener is properly attached. -
Persist scroll position – Extend
useScrollToElementto:- Save the sidebar scroll position to
localStorageon every scroll event (debounced). - On mount, restore from
NavigationStateContext(same-session navigation) or fall back tolocalStorage
(full page refresh), whichever is available.
- Save the sidebar scroll position to
Files Changed
components/Sidebar/index.jsx– useuseLayoutEffectto acquire ref to<aside>hooks/useScrollToElement.js– add localStorage read on mount and write on scrollhooks/useScroll.js– useonScrollRefpattern to avoid stale closure ononScrollcallback
Expected Behaviour
| Action | Before | After |
|---|---|---|
| Navigate to another page | Sidebar resets to top | Sidebar stays at last scroll position |
| Hard refresh (F5) | Sidebar resets to top | Sidebar restores from localStorage |
Notes
SideBarfrom@node-core/ui-componentsneeds to supportforwardReffor this to work without
theuseLayoutEffectworkaround. A separate issue/PR upstream on that package may be worth considering.- The
useScrollhook dependency onref.current(instead ofref) ensures the listener is attached
after the DOM element is available.
Activity