

# Outline

In-page outline navigation. Pass a flat `items` array (or `Outline.Item` children) and highlight via controlled `activeId` or automatic scroll-spy.

## Examples

### Default

Flat section links with a controlled active item (scroll-spy off).

```tsx
import { Outline } from '@var-ui/react';

<Outline
  activeId="intro"
  scrollSpy={false}
  items={[
    { id: 'intro', text: 'Intro', level: 2 },
    { id: 'examples', text: 'Examples', level: 2 },
  ]}
/>
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

### Nested items

Use `level: 3` for subsections — nested links indent under their parent heading.

```tsx
import { Outline } from '@var-ui/react';

<Outline
  activeId="examples"
  scrollSpy={false}
  items={[
    { id: 'intro', text: 'Intro', level: 2 },
    { id: 'examples', text: 'Examples', level: 2 },
    { id: 'default', text: 'Default', level: 3 },
    { id: 'nested', text: 'Nested', level: 3 },
  ]}
/>
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

## Props

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| activeId | string \| undefined | no |  | Controlled active item id — disables scroll-spy when set. |
| children | ReactNode | no |  | `Outline.Item` children, used when `items` is omitted. |
| className | string \| undefined | no |  |  |
| items | OutlineItemData[] \| undefined | no |  | Flat list of headings to render as links — takes priority over `Outline.Item` children. |
| scrollSpy | boolean \| undefined | no | true | Observe heading elements and highlight the topmost visible one when `activeId` is omitted. |
| title | string \| undefined | no | 'On this page' | Accessible name for the `nav` landmark and the visible heading. |

## Accessibility

The root is a `nav` landmark named by `title` (default “On this page”). Links target `#id` — keep matching heading `id`s in the page. When scroll-spy is on, the active link updates from an `IntersectionObserver`; pass `activeId` to control highlighting yourself.
