Skip to content
ARC UI ARC Reactive Components
Docs Components Tokens Synthesizer
v2.1.0
Getting Started Frameworks Design Tokens Theming Theme Synthesizer Accessibility Browser Support Changelog Contributing All Components App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageInfinite ScrollMarqueeScroll AreaSeparatorSkeletonSpinnerStackVirtual List Animated NumberBadgeComparisonCountdown TimerData TableDescription ListDiffKey ValueListMeterSparklineStatStepperTableTagTimelineValue Card BlockquoteCode BlockGradient TextHighlightKbdMarkdownNumber FormatProseTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerFieldsetFile UploadFormHotkeyIcon ButtonInputInput GroupLabelMulti SelectNumber InputOTP InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSliderSortable ListSwitch GroupTextareaTheme ToggleTime PickerToggle AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
Components Scroll Spy
navigation interactive
<arc-scroll-spy>

Overview

Guidelines

When to use

  • Place ScrollSpy in a sidebar-right or sticky aside column next to the scrollable content
  • Give every target section a unique id attribute that matches the spy-link target
  • Set the offset prop to match the height of your sticky header or TopBar
  • Listen for the arc-change event to synchronize breadcrumbs, analytics, or URL hash updates
  • Keep spy-link labels short -- they should match or abbreviate section headings

When not to use

  • Use ScrollSpy for primary site navigation -- it is for in-page section tracking only
  • Forget to import arc-spy-link; ScrollSpy depends on it to collect its link definitions
  • Place ScrollSpy inside a scrollable container other than the document -- the observer watches document-level intersections
  • Add dozens of spy-links to a single ScrollSpy; more than 10-12 links make the list hard to scan
  • Omit the target attribute on spy-links -- they will be silently ignored by the observer

Features

  • IntersectionObserver-based scroll tracking with zero scroll-event overhead
  • Declarative link registration via <arc-spy-link target="id"> children
  • Sticky positioning with automatic height capping to prevent overflow
  • Smooth-scroll click navigation to target sections
  • Active link highlighting with accent-primary background and aria-current="true"
  • Configurable offset prop to account for sticky headers of varying heights
  • arc-change custom event dispatched when the active section changes
  • Thin scrollbar styling for long tables of contents

Preview

Overview Installation Usage API Reference Examples

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<arc-scroll-spy>
  <arc-spy-link target="section-1">Section 1</arc-spy-link>
  <arc-spy-link target="section-2">Section 2</arc-spy-link>
</arc-scroll-spy>
import { ScrollSpy, SpyLink } from '@arclux/arc-ui-react';

<ScrollSpy>
  <SpyLink target="section-1">Section 1</SpyLink>
  <SpyLink target="section-2">Section 2</SpyLink>
</ScrollSpy>
<script setup>
import { ScrollSpy, SpyLink } from '@arclux/arc-ui-vue';
</script>

<template>
  <ScrollSpy>
    <SpyLink target="section-1">Section 1</SpyLink>
    <SpyLink target="section-2">Section 2</SpyLink>
  </ScrollSpy>
</template>
<script>
  import { ScrollSpy, SpyLink } from '@arclux/arc-ui-svelte';
</script>

<ScrollSpy>
  <SpyLink target="section-1">Section 1</SpyLink>
  <SpyLink target="section-2">Section 2</SpyLink>
</ScrollSpy>
import { Component } from '@angular/core';
import { ScrollSpy, SpyLink } from '@arclux/arc-ui-angular';

@Component({
  imports: [ScrollSpy, SpyLink],
  template: `
    <ScrollSpy>
      <SpyLink target="section-1">Section 1</SpyLink>
      <SpyLink target="section-2">Section 2</SpyLink>
    </ScrollSpy>
  `,
})
export class MyComponent {}
import { ScrollSpy, SpyLink } from '@arclux/arc-ui-solid';

<ScrollSpy>
  <SpyLink target="section-1">Section 1</SpyLink>
  <SpyLink target="section-2">Section 2</SpyLink>
</ScrollSpy>
import { ScrollSpy, SpyLink } from '@arclux/arc-ui-preact';

<ScrollSpy>
  <SpyLink target="section-1">Section 1</SpyLink>
  <SpyLink target="section-2">Section 2</SpyLink>
</ScrollSpy>

API

Prop Type Default Description
active string '' The id of the currently active section. Reflects to an attribute and updates automatically as the user scrolls.
offset number 80 Pixel offset from the top of the viewport used in the IntersectionObserver rootMargin. Increase this value to account for taller sticky headers.

Events

Event Description
arc-change Fired when the active spy target changes during scroll

See Also