Skip to content

Commit

Permalink
docs: Opting out of scrolling with next/link and useRouter. (#53804)
Browse files Browse the repository at this point in the history
Addressing comments from #49087.
Introduced with #51869.
Related #50105.

This PR adds documentation for `next/link` and useRouter` about how to disable scroll restoration.
  • Loading branch information
leerob committed Aug 10, 2023
1 parent d4ff236 commit 1286e14
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function Navigation({ navLinks }) {

#### Scrolling to an `id`

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.
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 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.

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

#### Disabling scroll restoration

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()`.

```jsx
// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
```

```jsx
// useRouter
import { useRouter } from 'next/navigation'

router.push('/dashboard', { scroll: false })
```

## `useRouter()` Hook

The `useRouter` hook allows you to programmatically change routes.
Expand Down
29 changes: 29 additions & 0 deletions docs/02-app/02-api-reference/01-components/link.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Here's a summary of the props available for the Link Component:
| ------------------------ | ------------------- | ---------------- | -------- |
| [`href`](#href-required) | `href="/dashboard"` | String or Object | Yes |
| [`replace`](#replace) | `replace={false}` | Boolean | - |
| [`scroll`](#scroll) | `scroll={false}` | Boolean | - |
| [`prefetch`](#prefetch) | `prefetch={false}` | Boolean | - |

> **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.
Expand Down Expand Up @@ -131,6 +132,34 @@ export default function Page() {
}
```

### `scroll`

**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.

```tsx filename="app/page.tsx" switcher
import Link from 'next/link'

export default function Page() {
return (
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
)
}
```

```jsx filename="app/page.js" switcher
import Link from 'next/link'

export default function Page() {
return (
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
)
}
```

### `prefetch`

**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.
Expand Down
66 changes: 55 additions & 11 deletions docs/02-app/02-api-reference/04-functions/use-router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export default function Page() {

## `useRouter()`

- `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.
- `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).
- `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.
- `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).
- `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).
- `router.prefetch(href: string)`: [Prefetch](/docs/app/building-your-application/routing/linking-and-navigating#1-prefetching) the provided route for faster client-side transitions.
- `router.back()`: Navigate back to the previous route in the browser’s history stack.
Expand All @@ -53,18 +53,18 @@ export default function Page() {
> - The `<Link>` component automatically prefetch routes as they become visible in the viewport.
> - `refresh()` could re-produce the same result if fetch requests are cached. Other dynamic functions like `cookies` and `headers` could also change the response.
> **Migrating from the `pages` directory:**
>
> - The new `useRouter` hook should be imported from `next/navigation` and not `next/router`
> - The `pathname` string has been removed and is replaced by [`usePathname()`](/docs/app/api-reference/functions/use-pathname)
> - The `query` object has been removed and is replaced by [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params)
> - `router.events` is not currently supported. [See below.](#router-events)
>
> [View the full migration guide](/docs/app/building-your-application/upgrading/app-router-migration).
### Migrating from `next/router`

- The `useRouter` hook should be imported from `next/navigation` and not `next/router` when using the App Router
- The `pathname` string has been removed and is replaced by [`usePathname()`](/docs/app/api-reference/functions/use-pathname)
- The `query` object has been removed and is replaced by [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params)
- `router.events` has been replaced. [See below.](#router-events)

[View the full migration guide](/docs/app/building-your-application/upgrading/app-router-migration).

## Examples

### Router Events
### Router events

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

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

> **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).
### Disabling scroll restoration

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()`.

```tsx filename="app/example-client-component.tsx" switcher
'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
const router = useRouter()

return (
<button
type="button"
onClick={() => router.push('/dashboard', { scroll: false })}
>
Dashboard
</button>
)
}
```

```jsx filename="app/example-client-component.jsx" switcher
'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
const router = useRouter()

return (
<button
type="button"
onClick={() => router.push('/dashboard', { scroll: false })}
>
Dashboard
</button>
)
}
```

## Version History

| Version | Changes |
| --------- | ---------------------------------------------- |
| `v13.0.0` | `useRouter` from `next/navigation` introduced. |

0 comments on commit 1286e14

Please sign in to comment.