Scroll Indicator

A vertical TOC-style scroll indicator with tick marks, section labels, and a position readout. Tracks scroll and highlights the active section.

Dependencies

motion

Interaction Type

Scroll content to see indicator move. Hover for micro-clicks and to reveal section labels. Click any label for click audio and smooth section jumping.

Props

Options you can pass to customize this component.

Prop
Type
Description
sections*
Section[]

Array of section objects with id, title, and level (2 for h2, 3 for h3).

activeIndex
number

Controlled active section index. When set, the component does not manage its own state.

onIndexChange
(index: number) => void

Called when the active section changes via click.

scrollRef
RefObject<HTMLDivElement>

Ref to the scrollable container for automatic scroll tracking.

scrollOffset
number

Gap in px between the container top and a heading after clicking its section. Defaults to 16.

className
string

Additional CSS classes.

Installation

npx shadcn@latest addhttps://ui.nexvyn.dev/r/scroll-indicator.json

How to use

import { ScrollIndicator } from "@/components/ui/scroll-indicator"

const sections = [
  { id: "intro", title: "Introduction", level: 2 },
  { id: "setup", title: "Setup", level: 2 },
  { id: "config", title: "Configuration", level: 3 },
]

export function Demo() {
  return <ScrollIndicator sections={sections} />
}

Source Code

Click the code icon in the top-right corner to view the source code.

Contact

Questions or feedback? Reach out anytime.

License & Usage

  • •Free for personal and commercial use
  • •No attribution required
  • •Cannot be resold as a standalone product
  • •Anatomy/blueprint diagrams are licensed separately (CC BY-NC 4.0) and are not for commercial use
// No code loaded.

For best experience, open in browser on a wider screen

Philosophy

Nexvyn UI focuses on clarity and restraint. Each component has one signature motion moment, the accent appears only on focus, selection, or that signature, and everything else stays neutral. The goal is interfaces that feel built with care rather than assembled from parts. Components are small, readable, and meant to be copied into your project and owned by you.

Design System

Colors come from a short list of semantic tokens: background, foreground, muted, border, surface, and a single accent. Every token has a light and a dark value, so components follow the theme without any component-level dark mode code. Radii use rounded-md, spacing sits on a 4px grid, and type uses a small set of sizes at regular weight.

Animations

Motion uses spring physics and a small set of duration and easing tokens. Elements entering or leaving use ease-out, elements already on screen use ease-in-out, and hovers use plain ease. Only transform, opacity, clip-path, and filter are animated, and every animation respects the reduced motion setting by turning itself off.

Performance

Components animate hardware-friendly properties, clean up every timer, listener, and observer on unmount, and avoid reading layout during render. The documentation site is prerendered as static pages, heavy views such as anatomy diagrams load only when opened, and each component installs as its own file so you ship only what you use.

Accessibility

Components use semantic elements, keyboard support, visible focus rings for keyboard users, and ARIA attributes where native semantics are not enough. Composite widgets use roving focus, overlays trap and restore focus, and touch targets aim for 44 by 44 pixels. Contrast is checked by hand in both themes.

Developer Experience

Everything is typed with TypeScript, props follow a consistent naming pattern, and components support both controlled and uncontrolled use. Styling merges through a cn helper, so your className always wins. Install any component with a single shadcn command, then read and change the source like your own code.

Customization

Override the design tokens to match your brand, pass className to adjust layout, and swap icons, since icons are accepted as React nodes. User-facing strings such as labels and placeholders are props with sensible defaults, so the components are easy to localize without editing their source.

npx shadcn@latest addhttps://ui.nexvyn.dev/r/scroll-indicator.json