Skip to main content
Clever Ops

Article TOC Rail

Sticky table-of-contents rail for React articles, mono indices, a hairline spine, and a primary tick that slides to the active heading via built-in scroll-spy. Tailwind tokens throughout.

Preview & code

Loading Article TOC Rail preview

Installation

pnpm dlx shadcn@latest add @cleverui/article-toc-rail

Requires the @cleverui registry in your components.json, a one-off, two-line setup.

Usage

tsx
import { ArticleTocRail } from '@/components/blocks/article-toc-rail'
Exampletsx
import { ArticleTocRail } from '@/components/blocks/article-toc-rail'

const TOC_ITEMS = [
  { label: 'Why the status board failed', href: '#why-failed' },
  { label: 'Progressive disclosure model', href: '#disclosure' },
  { label: 'Signal tiers', href: '#signal-tiers', depth: 2 as const },
  { label: 'Mute windows', href: '#mute-windows', depth: 2 as const },
  { label: 'Rollout at Meridian Ops', href: '#rollout' },
  { label: 'What we measure now', href: '#measure' },
]

const SECTIONS = [
  {
    id: 'why-failed',
    title: 'Why the status board failed',
    body: [
      'Meridian Ops ran a single wall of red for eighteen months. Every pod, queue, and third-party webhook shared the same badge weight, so the 03:00 page always looked identical to a deploy-day blip.',
      'Mean time to context sat at eleven minutes. Engineers were not slow, the board was. Nothing ranked, nothing aged out, and nothing told you which fire could wait until morning.',
    ],
  },
  {
    id: 'disclosure',
    title: 'Progressive disclosure model',
    body: [
      'The rebuild splits risk into three bands: page-now, watch-this-shift, and ledger-only. Only the first band can interrupt sleep. The second lives on a quiet strip. The third is searchable history.',
      'Operators expand a band to see contributing services; they never see twenty peers screaming at the same volume. One accent line marks the active band, never a rainbow of severity chips.',
    ],
  },
  {
    id: 'signal-tiers',
    title: 'Signal tiers',
    body: [
      'Tier A pages on-call when a customer-facing SLO is breached for two consecutive windows. Tier B surfaces on the shift strip with a mono index and owner. Tier C writes to the ledger without UI chrome.',
    ],
  },
  {
    id: 'mute-windows',
    title: 'Mute windows',
    body: [
      'Deploy freezes and planned failovers open a named mute window. Alerts still record; they simply do not page. Windows require a ticket id and an end time, open-ended mutes are rejected at the API.',
    ],
  },
  {
    id: 'rollout',
    title: 'Rollout at Meridian Ops',
    body: [
      'Week one shadowed the old board for the platform team. Week two cut paging for three non-customer services. By week four the carousel was gone and the night rotation dropped from five to three.',
      'The sticky contents rail on long RFCs reused the same index grammar as the board, two-digit mono labels, one primary tick, so engineers already knew how to read it.',
    ],
  },
  {
    id: 'measure',
    title: 'What we measure now',
    body: [
      'Time-to-context is the north star: median under ninety seconds for Tier A. Secondary metrics are pages-per-night and false-mute rate. We publish both on the weekly ops note, not a vanity dashboard.',
    ],
  },
] as const

export default function ArticleTocRailDemo() {
  return (
    <div className="mx-auto w-full max-w-6xl px-4 py-12 sm:px-6 sm:py-16">
      <div className="mb-10 max-w-2xl">
        <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-muted-foreground sm:text-xs">
          Engineering · Field notes
        </p>
        <h1 className="mt-3 text-balance text-3xl font-semibold tracking-tight text-foreground sm:text-4xl">
          Designing calm dashboards that still surface risk
        </h1>
        <p className="mt-4 text-base leading-relaxed text-muted-foreground">
          Scroll the longform, the rail tracks the heading in view with a single
          primary tick on a hairline spine.
        </p>
      </div>

      <div className="grid gap-10 lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-14">
        <ArticleTocRail items={TOC_ITEMS} sticky />

        <article className="min-w-0 max-w-prose">
          {SECTIONS.map((section) => (
            <section
              key={section.id}
              id={section.id}
              className="scroll-mt-28 border-t border-border/60 py-10 first:border-t-0 first:pt-0 sm:py-12"
            >
              <h2 className="text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
                {section.title}
              </h2>
              <div className="mt-4 space-y-4 text-sm leading-relaxed text-muted-foreground sm:text-base">
                {section.body.map((para) => (
                  <p key={para.slice(0, 24)}>{para}</p>
                ))}
              </div>
            </section>
          ))}
        </article>
      </div>
    </div>
  )
}

API reference

ArticleTocRail accepts the following props.

PropTypeDefaultDescription
items*ArticleTocRailItem[]headings to track; href is the in-page anchor
eyebrowstring'Contents'mono micro-label above the list
activeHrefstringcontrolled active item; omit to let the built-in scroll-spy (IntersectionObserver on anchor targets, post-mount) drive it
stickybooleantruesticky with top offset when true; static rail for previews when false
labelstring'Table of contents'accessible name for the nav landmark

…plus everything from React.HTMLAttributes<HTMLElement>: className, event handlers, aria attributes and the rest pass straight through.

Referenced types

Typestsx
export interface ArticleTocRailItem {
  label: string
  /** in-page anchor, e.g. '#setup' */
  href: string
  /** 2 renders as an indented subsection without an index */
  depth?: 1 | 2
}

Frequently asked questions

How do I install the Article TOC Rail component?

Register the @cleverui registry in your components.json ("@cleverui": "https://cleverops.com.au/r/{name}.json"), then run `npx shadcn@latest add @cleverui/article-toc-rail`. The shadcn CLI copies the source into your project, you own the code from that point. You can also copy the source directly from this page.

What dependencies does Article TOC Rail require?

Article TOC Rail uses motion on top of React and Tailwind CSS. You don't need to install it manually, the shadcn CLI resolves and installs npm dependencies automatically when you add the component.

Can I theme Article TOC Rail to match my brand?

Yes. The component is styled entirely with Tailwind utilities over standard design tokens (primary, background, muted, border), so it inherits your existing shadcn/ui theme automatically. Change your CSS variables and the component follows, no source edits needed for palette, radius, or fonts.

Want this built for you?

CleverUI is built by the Clever Ops web team. If you'd rather ship a hand-coded, fast, custom website than assemble one, we build them for Australian businesses every week.

Explore web development services