a1ui

Section Rail

A compact reading rail that tracks progress through page sections.

Read agent guide

Demo

Overview

A quick read of the page.

Goals

What the work needs to solve.

Scope

The boundaries of the work.

Approach

The chosen direction.

Structure

How the pieces fit together.

Components

The parts used in the interface.

States

Pending, active, and complete.

Motion

How the rail responds.

Accessibility

Labels and keyboard focus.

Performance

Keeping updates lightweight.

Delivery

What ships with the component.

Summary

The final result.

Installation

pnpm dlx shadcn@latest add https://ui.arjayby1.xyz/r/section-rail.json

Code

import { SectionRail } from "@/components/ui/section-rail";

const sections = [
  { id: "overview", label: "Overview" },
  { id: "installation", label: "Installation" },
  { id: "api-reference", label: "API reference" },
];

export function ArticlePage() {
  return (
    <>
      <SectionRail
        sections={sections}
        activeMarkerLength="short"
        gap={0}
        className="fixed top-1/2 left-4 -translate-y-1/2"
      />
      <article>{/* Sections with matching IDs */}</article>
    </>
  );
}

API reference

PropTypeDefaultPurpose
sections{ id: string; label: string }[]RequiredMaps each marker to an element ID and readable label.
activeOffsetnumber0.36Sets the reading line within the nearest scroll container.
activeMarkerLength"long" | "short""long"Sets the resting width of the active marker.
ariaLabelstring"Page sections"Names the navigation landmark.
gapCSSProperties["gap"]0Sets the gap between section markers.
classNamestringNoneControls placement in the consuming page.

The active link receives aria-current="location". Use activeMarkerLength="short" to keep it at the base width or "long" to extend it. Both options retain the full-opacity active color. Every link also exposes data-state="pending", active, or complete for styling. Hovering or focusing a link expands the nearby markers into a tapered group.