Outline

Follows your reading position in the page outline.

Installation

Scroll the page and the line beside the outline follows the section you are reading.

Usage

Scroll the page and the line beside the outline follows the section you are reading.

Props

Scroll the page and the line beside the outline follows the section you are reading.

Events

Scroll the page and the line beside the outline follows the section you are reading.

Accessibility

Scroll the page and the line beside the outline follows the section you are reading.

Installation

pnpm dlx shadcn@latest add @paneui/outline

Usage

Composition

Examples

Popover

Use below the breakpoint where the rail no longer fits, or on full-width pages.

RTL

Headings

Items point at headings by id, so ids from rehype-slug or your own anchors both work. The list renders on the server; the track and the current section are measured after hydration.

Current section

A heading is current once its top passes activeLine (px from the top of the viewport) by 8px, and stays current until it moves back 8px, so a heading resting on the line never flickers. Over the last screen of scroll the line slides to the bottom edge, so short sections at the end each light up in turn. A clicked entry holds while the page scrolls to it. Set activeLine below your sticky header.

Motion

The lit stretch of the track slides between entries over 300ms; under reduced motion it moves without a transition. When the list scrolls, it moves only as far as the current entry needs and without animation, so it never fights the page scroll.

API Reference

Outline

Also accepts every prop of nav.

items*
readonly OutlineItem[]
{ id, title, depth }, with depth 2 for an h2 and 3 for an h3.
title= `labels.onThisPage`
React.ReactNode
Heading above the list; null hides it. The default comes from the locale.
activeLine= 112
number
Px from the top of the viewport a heading must pass to become current.
backToTop= true
boolean
Shows the locale's backToTop link under the list after 320px of scrolling. The row and its divider fade in together; before that the row keeps its space but shows nothing.
maxHeight= "calc(100svh - 6.5rem)"
string
Cap for the outline; the list scrolls inside it.
renderLink
(props, item) => React.ReactElement
Swap each <a> for your own element; spread props onto it.
PropTypeDefaultDescription
items*readonly OutlineItem[]—{ id, title, depth }, with depth 2 for an h2 and 3 for an h3.
titleReact.ReactNode`labels.onThisPage`Heading above the list; null hides it. The default comes from the locale.
activeLinenumber112Px from the top of the viewport a heading must pass to become current.
backToTopbooleantrueShows the locale's backToTop link under the list after 320px of scrolling. The row and its divider fade in together; before that the row keeps its space but shows nothing.
maxHeightstring"calc(100svh - 6.5rem)"Cap for the outline; the list scrolls inside it.
renderLink(props, item) => React.ReactElement—Swap each <a> for your own element; spread props onto it.

OutlinePopover

The trigger fills the nav, so size it with className. Also accepts every prop of nav.

items*
readonly OutlineItem[]
Same as Outline.
title= `labels.onThisPage`
React.ReactNode
Button label before the current section. The default comes from the locale.
activeLine= 112
number
Same as Outline.
backToTop= true
boolean
Back to top in the popover once the page has scrolled.
renderLink
(props, item) => React.ReactElement
Same as Outline.
PropTypeDefaultDescription
items*readonly OutlineItem[]—Same as Outline.
titleReact.ReactNode`labels.onThisPage`Button label before the current section. The default comes from the locale.
activeLinenumber112Same as Outline.
backToTopbooleantrueBack to top in the popover once the page has scrolled.
renderLink(props, item) => React.ReactElement—Same as Outline.

useActiveHeading

useActiveHeading(ids, { line }) returns the id of the section being read.

ids*
readonly string[]
Heading ids in page order.
line= 112
number
Px from the top of the viewport.
PropTypeDefaultDescription
ids*readonly string[]—Heading ids in page order.
linenumber112Px from the top of the viewport.