EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Outline·component·@astryxdesign/core

Outline

A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes. Features a sliding indicator track that animates to the active heading. The list is a single tab stop: arrow keys move between headings, Home/End jump to the ends, and Enter/Space activate.

Open in Playground @astryxdesign/core/Outline

Showcases and examples

4 documented examples

Outline

A document outline with the active section highlighted by the sliding indicator track.

Preview loads on approachPreview loads on approach
Exact source · outline-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {Outline} from '@astryxdesign/core/Outline';
import type {OutlineItem} from '@astryxdesign/core/Outline';

const items: OutlineItem[] = [
  {id: 'showcase-overview', label: 'Overview', level: 2},
  {id: 'showcase-installation', label: 'Installation', level: 2},
  {id: 'showcase-theming', label: 'Theming', level: 2},
  {id: 'showcase-tokens', label: 'Tokens', level: 3},
  {id: 'showcase-accessibility', label: 'Accessibility', level: 2},
];

export default function OutlineShowcase() {
  return (
    <div style={{width: 240}}>
      <Outline items={items} activeId="showcase-theming" />
    </div>
  );
}

Usage

A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes. Features a sliding indicator track that animates to the active heading. The list is a single tab stop: arrow keys move between headings, Home/End jump to the ends, and Enter/Space activate.

  • Pass a flat ordered list of headings and let level control indentation.
  • Use activeId when custom scroll logic owns the active section.
  • Use density="compact" in dense sidebars where vertical space is tight.
  • Use useOutlineFromMarkdown or useOutlineFromDOM when headings are generated from content.
  • Pass scrollContainerRef when the content scrolls in a split pane, modal, or panel instead of the viewport.
  • Set offset to the height of a fixed header that overlays the content, so headings land below it instead of underneath it.
  • Use Outline for application navigation - use SideNav or TopNav for routes.
  • Use Outline for expandable hierarchy - use TreeList when nodes need expand and collapse.
  • Rely on onNavigateEnd to mean "arrived" - it also fires when the user interrupts the scroll.

Typed props

PropType and behavior
itemsOutlineItem[] · required
Ordered heading items. Each item has id, label, and level (1-6). The id should match the target heading element id.
activeIdstring
Currently active heading id. Providing this prop makes active state controlled and disables built-in scroll-spy.
onActiveIdChange(id: string) => void
Called when the active item changes from built-in scroll-spy or from an outline link click.
labelstring · default 'Table of contents'
Accessible label for the nav landmark.
density'default' | 'compact' · default 'default'
Density variant controlling item padding. 'compact' for dense UIs, 'default' for standard spacing.
onNavigateStart(id: string) => void
Called with the item id when navigation begins, before the scroll starts. Pair with onNavigateEnd to drive an arrival effect (flash, ring, pulse) on the target heading.
onNavigateEnd(id: string) => void
Called with the item id once the navigation resolves - when the smooth scroll settles, or when reduced motion turns it into an instant jump. Fires exactly once per onNavigateStart, including when the user interrupts the scroll, so a "navigating" state can never leak.
offsetnumber · default 0
Height in px of a fixed header overlaying the top of the scroll root. Shifts both the activation line and the scroll landing by the same amount, so a heading activates exactly where navigating to it puts it - below the header, not underneath it. Composes with each heading's own scroll-margin-top (the header, then the breathing room below it); it does not replace it. Leave at 0 when nothing overlays the content and let scroll-margin-top do the work.
scrollContainerRefReact.RefObject<HTMLElement | null>
Scroll container to track, instead of auto-detecting the nearest scrollable ancestor. Use it when content scrolls inside a split pane, modal, or dashboard panel rather than the viewport.
hasScrollOnClickboolean · default true
Whether activating an item smooth-scrolls to it. Set to false to own the scrolling yourself (virtualized content, a router): the Outline still updates the active item, the hash, and the navigate callbacks, but performs no scroll.
xstyleStyleXStyles
StyleX styles for layout customization. Must be a stylex.create() value.

Anatomy

Outline · required

Navigation container for the same-page heading links and indicator.

Heading link · required

Anchor for one heading, indented by level and marked when active.

Label · required

Heading text displayed inside its heading link.

Indicator track · required

Painted vertical rule behind the active indicator.

Active indicator · required

Sliding bar positioned beside the currently active heading link.

Theming

Targets

astryx-outline

Visual props: density

astryx-outline-indicator
astryx-outline-item

Visual props: level

States: active