Skip to content

Commit 1286e14

Browse files
authored
docs: Opting out of scrolling with next/link and useRouter. (#53804)
Addressing comments from #49087. Introduced with #51869. Related #50105. This PR adds documentation for `next/link` and useRouter` about how to disable scroll restoration.
1 parent d4ff236 commit 1286e14

File tree

3 files changed

+103
-12
lines changed

3 files changed

+103
-12
lines changed

docs/02-app/01-building-your-application/01-routing/03-linking-and-navigating.mdx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export function Navigation({ navLinks }) {
9595

9696
#### Scrolling to an `id`
9797

98-
The default behavior of `<Link>` is to scroll to the top of a new route or to maintain the scroll position for backwards and forwards navigation.
98+
The default behavior of the Next.js App Router is to scroll to the top of a new route or to maintain the scroll position for backwards and forwards navigation.
9999

100100
If you'd like to scroll to a specific `id` on navigation, you can append your URL with a `#` hash link or just pass a hash link to the `href` prop. This is possible since `<Link>` renders to an `<a>` element.
101101

@@ -106,6 +106,24 @@ If you'd like to scroll to a specific `id` on navigation, you can append your UR
106106
<a href="/dashboard#settings">Settings</a>
107107
```
108108

109+
#### Disabling scroll restoration
110+
111+
The default behavior of the Next.js App Router is to scroll to the top of a new route or to maintain the scroll position for backwards and forwards navigation. If you'd like to disable this behavior, you can pass `scroll={false}` to the `<Link>` component, or `scroll: false` to `router.push()` or `router.replace()`.
112+
113+
```jsx
114+
// next/link
115+
<Link href="/dashboard" scroll={false}>
116+
Dashboard
117+
</Link>
118+
```
119+
120+
```jsx
121+
// useRouter
122+
import { useRouter } from 'next/navigation'
123+
124+
router.push('/dashboard', { scroll: false })
125+
```
126+
109127
## `useRouter()` Hook
110128

111129
The `useRouter` hook allows you to programmatically change routes.

docs/02-app/02-api-reference/01-components/link.mdx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Here's a summary of the props available for the Link Component:
7777
| ------------------------ | ------------------- | ---------------- | -------- |
7878
| [`href`](#href-required) | `href="/dashboard"` | String or Object | Yes |
7979
| [`replace`](#replace) | `replace={false}` | Boolean | - |
80+
| [`scroll`](#scroll) | `scroll={false}` | Boolean | - |
8081
| [`prefetch`](#prefetch) | `prefetch={false}` | Boolean | - |
8182

8283
> **Good to know**: `<a>` tag attributes such as `className` or `target="_blank"` can be added to `<Link>` as props and will be passed to the underlying `<a>` element.
@@ -131,6 +132,34 @@ export default function Page() {
131132
}
132133
```
133134

135+
### `scroll`
136+
137+
**Defaults to `true`.** The default behavior of `<Link>` is to scroll to the top of a new route or to maintain the scroll position for backwards and forwards navigation. When `false`, `next/link` will _not_ scroll to the top of the page after a navigation.
138+
139+
```tsx filename="app/page.tsx" switcher
140+
import Link from 'next/link'
141+
142+
export default function Page() {
143+
return (
144+
<Link href="/dashboard" scroll={false}>
145+
Dashboard
146+
</Link>
147+
)
148+
}
149+
```
150+
151+
```jsx filename="app/page.js" switcher
152+
import Link from 'next/link'
153+
154+
export default function Page() {
155+
return (
156+
<Link href="/dashboard" scroll={false}>
157+
Dashboard
158+
</Link>
159+
)
160+
}
161+
```
162+
134163
### `prefetch`
135164

136165
**Defaults to `true`.** When `true`, `next/link` will prefetch the page (denoted by the `href`) in the background. This is useful for improving the performance of client-side navigations. Any `<Link />` in the viewport (initially or through scroll) will be preloaded.

docs/02-app/02-api-reference/04-functions/use-router.mdx

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export default function Page() {
4141

4242
## `useRouter()`
4343

44-
- `router.push(href: string)`: Perform a client-side navigation to the provided route. Adds a new entry into the [browser’s history](https://developer.mozilla.org/en-US/docs/Web/API/History_API) stack.
45-
- `router.replace(href: string)`: Perform a client-side navigation to the provided route without adding a new entry into the [browser’s history stack](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
44+
- `router.push(href: string, { scroll: boolean })`: Perform a client-side navigation to the provided route. Adds a new entry into the [browser’s history](https://developer.mozilla.org/en-US/docs/Web/API/History_API) stack.
45+
- `router.replace(href: string, { scroll: boolean })`: Perform a client-side navigation to the provided route without adding a new entry into the [browser’s history stack](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
4646
- `router.refresh()`: Refresh the current route. Making a new request to the server, re-fetching data requests, and re-rendering Server Components. The client will merge the updated React Server Component payload without losing unaffected client-side React (e.g. `useState`) or browser state (e.g. scroll position).
4747
- `router.prefetch(href: string)`: [Prefetch](/docs/app/building-your-application/routing/linking-and-navigating#1-prefetching) the provided route for faster client-side transitions.
4848
- `router.back()`: Navigate back to the previous route in the browser’s history stack.
@@ -53,18 +53,18 @@ export default function Page() {
5353
> - The `<Link>` component automatically prefetch routes as they become visible in the viewport.
5454
> - `refresh()` could re-produce the same result if fetch requests are cached. Other dynamic functions like `cookies` and `headers` could also change the response.
5555
56-
> **Migrating from the `pages` directory:**
57-
>
58-
> - The new `useRouter` hook should be imported from `next/navigation` and not `next/router`
59-
> - The `pathname` string has been removed and is replaced by [`usePathname()`](/docs/app/api-reference/functions/use-pathname)
60-
> - The `query` object has been removed and is replaced by [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params)
61-
> - `router.events` is not currently supported. [See below.](#router-events)
62-
>
63-
> [View the full migration guide](/docs/app/building-your-application/upgrading/app-router-migration).
56+
### Migrating from `next/router`
57+
58+
- The `useRouter` hook should be imported from `next/navigation` and not `next/router` when using the App Router
59+
- The `pathname` string has been removed and is replaced by [`usePathname()`](/docs/app/api-reference/functions/use-pathname)
60+
- The `query` object has been removed and is replaced by [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params)
61+
- `router.events` has been replaced. [See below.](#router-events)
62+
63+
[View the full migration guide](/docs/app/building-your-application/upgrading/app-router-migration).
6464

6565
## Examples
6666

67-
### Router Events
67+
### Router events
6868

6969
You can listen for page changes by composing other Client Component hooks like `usePathname` and `useSearchParams`.
7070

@@ -112,6 +112,50 @@ export default function Layout({ children }) {
112112

113113
> **Good to know**: `<NavigationEvents>` is wrapped in a [`Suspense` boundary](/docs/app/building-your-application/routing/loading-ui-and-streaming#example) because[`useSearchParams()`](/docs/app/api-reference/functions/use-search-params) causes client-side rendering up to the closest `Suspense` boundary during [static rendering](/docs/app/building-your-application/rendering/static-and-dynamic#static-rendering-default). [Learn more](/docs/app/api-reference/functions/use-search-params#behavior).
114114
115+
### Disabling scroll restoration
116+
117+
By default, Next.js will scroll to the top of the page when navigating to a new route. You can disable this behavior by passing `scroll: false` to `router.push()` or `router.replace()`.
118+
119+
```tsx filename="app/example-client-component.tsx" switcher
120+
'use client'
121+
122+
import { useRouter } from 'next/navigation'
123+
124+
export default function Page() {
125+
const router = useRouter()
126+
127+
return (
128+
<button
129+
type="button"
130+
onClick={() => router.push('/dashboard', { scroll: false })}
131+
>
132+
Dashboard
133+
</button>
134+
)
135+
}
136+
```
137+
138+
```jsx filename="app/example-client-component.jsx" switcher
139+
'use client'
140+
141+
import { useRouter } from 'next/navigation'
142+
143+
export default function Page() {
144+
const router = useRouter()
145+
146+
return (
147+
<button
148+
type="button"
149+
onClick={() => router.push('/dashboard', { scroll: false })}
150+
>
151+
Dashboard
152+
</button>
153+
)
154+
}
155+
```
156+
157+
## Version History
158+
115159
| Version | Changes |
116160
| --------- | ---------------------------------------------- |
117161
| `v13.0.0` | `useRouter` from `next/navigation` introduced. |

0 commit comments

Comments
 (0)