useScrollRestoration
A custom hook that saves and restores the previous scroll position of the browser or a specific element.
By default, it manages the window scroll, and you can use ref to manage a specific scrollable area.
Codeโ
Interfaceโ
interface UseScrollRestorationOptions {
id?: string;
enabled?: boolean;
behavior?: ScrollOptions['behavior'];
retry?: number;
}
function useScrollRestoration<T extends HTMLElement>({
id,
enabled,
behavior,
}?: UseScrollRestorationOptions): {
ref: React.RefObject<T | null>;
};
Optionsโ
| Name | Type | Default | Description |
|---|---|---|---|
id | string | 'window' or 'element' | Scroll restoration identifier (required when using multiple instances) |
enabled | boolean | true | Whether scroll restoration is enabled |
behavior | ScrollOptions['behavior'] | 'instant' | Scroll restoration behavior ('auto', 'instant', 'smooth') |
retry | number | 5 | Number of scroll restoration retries (with exponential backoff) |
Remarksโ
- When content is loaded asynchronously or due to image loading, the page height may be smaller than the saved scroll position.
- In such cases, it automatically retries using
exponential backoff, increasing the retry interval each time. - Retry intervals: 100ms โ 200ms โ 400ms โ 800ms โ 1600ms
- The default maximum number of retries is
5, which can be adjusted with theretryoption.
- In such cases, it automatically retries using
- When using the hook multiple times within a single component, assign explicit
idoptions to distinguish each instance.- If no
idis specified, the default is'element'when arefis present, or'window'otherwise. - Without an
id, duplicate keys may cause scroll restoration to malfunction โ use with caution.
- If no
- Scroll position is saved on
refresh,page navigation (back/forward), andhook unmount.- Therefore, if this hook is called in a component that remains mounted without unmounting (e.g., a Layout component), scroll restoration may not work correctly.
- If the URL has a
hash fragment (#section), scroll restoration is skipped.- This is to respect the user's clear intent for hash scrolling and to avoid conflicts with standard browser behavior.
- React Router provides its own
location.key. useScrollRestorationautomatically detects and uses it.- Per-page scroll positions are accurately restored without any additional configuration.
Usageโ
Window Scrollโ
import { useScrollRestoration } from '@modern-kit/react';
const Page = () => {
useScrollRestoration();
return (
<div>
{/* Long content... */}
</div>
);
};
Specific Elementโ
import { useScrollRestoration } from '@modern-kit/react';
const ScrollBox = () => {
const { ref } = useScrollRestoration<HTMLDivElement>();
return (
<div
ref={ref}
style={{ height: '500px', overflowY: 'auto' }}
>
{/* Content with internal scrolling */}
</div>
);
};
Multiple Instancesโ
When managing multiple scroll areas in a single component, assign a unique id to each instance.
import { useScrollRestoration } from '@modern-kit/react';
const MultiScrollPage = () => {
useScrollRestoration(); // window scroll (default id: 'window')
const { ref: sidebarRef } = useScrollRestoration<HTMLDivElement>({ id: 'sidebar' });
const { ref: contentRef } = useScrollRestoration<HTMLDivElement>({ id: 'content' });
return (
<div>
<aside ref={sidebarRef} style={{ height: '100vh', overflowY: 'auto' }}>
{/* Sidebar content */}
</aside>
<main ref={contentRef} style={{ height: '100vh', overflowY: 'auto' }}>
{/* Main content */}
</main>
</div>
);
};
Example (Window Scroll)โ
1. Scroll the page about halfway down.
2. Click the browser's 'Back' button.
3. Check that the scroll position is preserved.
Example1 (Scroll Restoration for a Specific Element)โ
A basic example for managing the scroll position of a specific area (e.g., a scrollable container).
Use ref to specify the element whose scroll position should be restored.
๐งช How to test
- Scroll the scroll box below about halfway (e.g., to around "Item 10")
- Click the browser's 'Back' button
- When you return, the scroll position is exactly restored! โจ
ref. The behavior: 'smooth' option applies a smooth restoration animation.Example2 (Scroll Restoration After Async Data Loading)โ
In real applications, data is often loaded asynchronously.
This example demonstrates that the scroll position is accurately restored even during data loading.
Internally, a retry mechanism (up to 5 times, with exponential backoff) waits until the content is fully loaded.
๐งช How to test
- Wait for the data to load (1 second)
- Scroll the scroll box about halfway
- Click the browser's 'Back' button
- When you return:
- "Loading..." is shown โ data finishes loading
- The scroll position is automatically restored to the previous position! ๐ฏ
- Retry intervals: 100ms โ 200ms โ 400ms โ 800ms โ 1600ms
- Max retries: 5 (default, configurable via the
retryoption)
Example3 (Multiple Instances)โ
When multiple scroll areas need to be managed independently on a single page, assign a unique id to each instance.
For example, when a sidebar and a main content area each have independent scrolling:
๐งช How to test
- Scroll the blue area (main content) about halfway.
- Scroll the green area (sidebar) about halfway.
- Click the browser's 'Back' button.
- When you return, both areas have their scroll positions accurately restored! โจ
id option distinguishes each instance.