Section Dots
InteractiveA scroll-spy side rail whose active dot stretches into a labelled pill, tracking the section in view with IntersectionObserver and smooth-scrolling on click.
Inspired by Skiper UI — Side Scroll Navigation (pattern) — independently built, not affiliated. Attribution policy
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/section-dots.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/section-dots.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div style={{ position: "relative", width: "100%", minHeight: 380, overflow: "hidden", borderRadius: 16, background: "radial-gradient(120% 120% at 12% 0%, #17151f 0%, #0f0f10 62%)", border: "1px solid rgba(255,255,255,0.08)" }}>
<div style={{ position: "absolute", inset: 0, padding: "30px 100px 30px 36px", display: "flex", flexDirection: "column", gap: 14 }}>
{[
{ id: "sd-intro", tag: "01", title: "Introduction", accent: "#8b5cf6" },
{ id: "sd-features", tag: "02", title: "Features", accent: "#ec4899" },
{ id: "sd-pricing", tag: "03", title: "Pricing", accent: "#f5a623" },
{ id: "sd-faq", tag: "04", title: "FAQ", accent: "#22d3ee" },
].map((s) => (
<div key={s.id} id={s.id} style={{ borderRadius: 14, padding: "14px 16px", background: "rgba(255,255,255,0.02)", border: "1px solid rgba(255,255,255,0.07)" }}>
<div style={{ fontSize: 11, letterSpacing: 2, fontFamily: "ui-monospace, monospace", color: s.accent }}>{s.tag}</div>
<div style={{ marginTop: 4, fontSize: 15, fontWeight: 600, color: "rgba(255,255,255,0.92)" }}>{s.title}</div>
<div style={{ height: 6, width: "58%", borderRadius: 999, marginTop: 10, background: "linear-gradient(90deg, " + s.accent + "66, transparent)" }} />
<div style={{ height: 6, width: "40%", borderRadius: 999, marginTop: 6, background: "rgba(255,255,255,0.08)" }} />
</div>
))}
</div>
<SectionDots
position="right"
className="absolute"
sections={[
{ id: "sd-intro", label: "Introduction" },
{ id: "sd-features", label: "Features" },
{ id: "sd-pricing", label: "Pricing" },
{ id: "sd-faq", label: "FAQ" },
]}
/>
</div>Props
SectionDotsProps extends Omit<React.HTMLAttributes<HTMLElement>, "children">
| Prop | Type | Default | Description |
|---|---|---|---|
| sections* | SectionDotItem[] | — | Ordered sections to track. One dot is rendered per entry, in order. |
| position | "right" | "left" | "right" | Which screen edge the rail pins to. Defaults to `"right"`. |
| offset | number | 0 | Pixels from the viewport top treated as the fold — subtracted from scroll targets and from the observer's top margin so a fixed header never hides the section a click lands on. Defaults to `0`. |
| accent | string | "#8b5cf6" | Accent for the active dot, pill ring, and focus ring. Mirrors `--pb-violet`. |
npm dependencies
- motion