- Overview
- Anatomy
- Header
- Navigation
- Renderers
SegmentSidebar is the "list" surface over a page-segmented result (partition
chunks or split subdocuments). Each row shows a color swatch, label, page
ranges, page count, and — when present — a confidence bar.
Hovering is a temporary preview. When nothing is hovered, currentPage derives
the highlighted segment. Clicking fires onSelect so the host can scroll the
document to the segment's first page; it does not persist category selection.
Wire it to the same useSegmentInteraction object as a
legend for a coordinated layout.
"use client";
import * as React from "react";
import { meanConfidence, toSegments } from "@/lib/segments";
import { SegmentSidebar } from "@/components/ui/segment-sidebar";
import { useSegmentInteraction } from "@/components/ui/use-segment-interaction";
// A split-style result (named subdocuments) with per-page likelihoods — the
// same model also covers partition chunks; only the label differs.In a split viewer
Mounted as the left rail of a split viewer, the sidebar shares preview and current-page state with the legend and page timeline. Hover a row to dim the others everywhere; click to scroll the document to that subdocument's first page.
"use client";
import { PdfViewerPages, PdfViewerProvider } from "@/components/ui/pdf-viewer";
import {
SplitViewer,
useSplitViewerDocumentControls,
} from "@/components/viewers/split/split-viewer";
const splitSource = {
kind: "url" as const,Architecture Boundary
FileViewerSidebar owns file-viewer placement, width, collapse state, and the
accessible label for the rail. SegmentSidebar owns only the segment-row model
and interaction semantics. Nesting SegmentSidebar inside
FileViewerSidebar is the intended composition when segments are the file
navigation content.
Internally, SegmentSidebar uses providerless SidebarList* primitives. That
keeps the row grammar aligned with the sidebar system without mounting an app
sidebar provider: no cookie persistence, no global shortcut, and no
viewport-level sidebar ownership.
Installation
pnpm dlx shadcn@latest add @retab/segment-sidebar
Usage
Reduce a partition or split result to Segment[] with toSegments, then render
the sidebar against your own interaction state:
import { toSegments } from "@/lib/segments";
import { SegmentSidebar } from "@/components/ui/segment-sidebar";
import { useSegmentInteraction } from "@/components/ui/use-segment-interaction";
// partition: [{ key, pages }] split: [{ name, pages }]
const segments = toSegments(result.output);
export function Example() {
const interaction = useSegmentInteraction();
return (
<SegmentSidebar
segments={segments}
interaction={interaction}
onSelect={(segment) => scrollToPage(segment.pages[0])}
unitLabel="subdocument"
/>
);
}For caller-owned preview state, build the same interaction object with
useControlledSegmentInteraction; do not pass selection props to the sidebar.
API Reference
| Prop | Type | Description |
|---|---|---|
segments | Segment[] | Labels + pages + colors (use toSegments). |
interaction | SegmentInteraction | Shared transient preview state. |
onSelect | (segment: Segment) => void | Fired when a segment is clicked, after transient preview is cleared. |
currentPage | number | null | 1-based current page; owning segments highlight when no preview exists. |
unitLabel | string | Row noun, e.g. "chunk" or "subdocument". Defaults to "segment". |
showUnused | boolean | Show segments with zero pages too. Defaults to true. |
className | string | Container class. |
Source
"use client";
import * as React from "react";
import {
getSegmentInteractionState,
getSegmentSurfaceProps,
scopeSegmentInteraction,
type SegmentInteraction,
} from "@/lib/segment-interaction";
import {
formatPageRanges,