Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/01-app/01-getting-started/04-linking-and-navigating.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,55 @@ export function LocaleSwitcher() {
)
}
```

### Scrolling with sticky headers

When navigating between routes, Next.js automatically scrolls to the top of the new content if it's not already visible. During this process, Next.js skips `sticky` and `fixed` positioned elements (like a navigation bar) to find the first scrollable content element.

This can cause content to appear behind a sticky header after navigation. You can fix this using the CSS [`scroll-padding-top`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top) property, which tells the browser to account for the sticky element's height when calculating scroll positions:

```css filename="app/globals.css"
html {
scroll-padding-top: 64px; /* Height of the sticky header */
}
```

```tsx filename="app/layout.tsx" switcher
import './globals.css'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<header className="sticky top-0 z-10 h-16 bg-white">
{/* Sticky navigation */}
</header>
{children}
</body>
</html>
)
}
```

```jsx filename="app/layout.js" switcher
import './globals.css'

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header className="sticky top-0 z-10 h-16 bg-white">
{/* Sticky navigation */}
</header>
{children}
</body>
</html>
)
}
```

This also works for hash fragment (`#id`) scrolling. See the [`<Link>` scroll prop](/docs/app/api-reference/components/link#scroll) for more details on how Next.js handles scroll behavior.
14 changes: 14 additions & 0 deletions docs/01-app/03-api-reference/02-components/link.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ When `scroll = {false}`, Next.js will not attempt to scroll to the first Page el

> **Good to know**: Next.js checks if `scroll: false` before managing scroll behavior. If scrolling is enabled, it identifies the relevant DOM node for navigation and inspects each top-level element. All non-scrollable elements and those without rendered HTML are bypassed, this includes sticky or fixed positioned elements, and non-visible elements such as those calculated with `getBoundingClientRect`. Next.js then continues through siblings until it identifies a scrollable element that is visible in the viewport.

#### Handling sticky headers with `scroll-padding-top`

Because Next.js skips `sticky` and `fixed` positioned elements when scrolling, it scrolls to the first visible non-sticky content element. If you have a sticky header (e.g., a navigation bar), the page content may appear to scroll "behind" the header, making it look like the scroll didn't go all the way to the top.

To fix this, use the CSS [`scroll-padding-top`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top) property on the scroll container (typically `html`) to account for the height of the sticky element:

```css filename="app/globals.css"
html {
scroll-padding-top: 64px; /* Height of the sticky header */
}
```

This tells the browser to offset any scroll-based positioning by the specified amount, ensuring content isn't hidden behind the sticky header. This works for both Next.js auto-scrolling and hash fragment (`#id`) scrolling.

<AppOnly>

```tsx filename="app/page.tsx" switcher
Expand Down
Loading