Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelogApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UIARC Radiant Components
v4.9DocsComponentsTokensSynthesizer
Getting StartedFrameworksServer RenderingDesign TokensThemingTheme SynthesizerTypographyUtilitiesAll ComponentsAccessibilityBrowser SupportChangelogContributingStatsApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Scroll Spy

Tracks scroll position and highlights the active navigation link.

ComponentsScroll Spy
navigationinteractive
<arc-scroll-spy>

Overview

ScrollSpy is a sticky table-of-contents component that watches the viewport and highlights whichever navigation link corresponds to the currently visible section. It uses an IntersectionObserver, so tracking does not block the main thread even on long pages with dozens of sections. Place it in a sidebar column next to your content. Each entry in the table of contents is declared with an `<arc-spy-link>` child element whose `target` attribute matches the `id` of a section on the page. ScrollSpy reads these declarative links from its slot, builds the IntersectionObserver, and renders a compact navigation list in its shadow DOM with an "On this page" heading. When the user scrolls a target section into view, the corresponding link receives an `aria-current="true"` attribute and a blue accent background highlight. Clicking a link smooth-scrolls to the target element and updates the active state immediately. The component dispatches an `arc-change` custom event with the active section ID whenever the highlighted link changes, so you can synchronize other UI (like a progress bar or breadcrumb) with the current reading position. The `offset` prop adjusts the scroll detection threshold to account for sticky headers of different heights.

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

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

Features

  • IntersectionObserver-based scroll tracking with no 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>

API

ringRadiusnumber6
Ring geometry. r drives the dasharray, so the two cannot drift apart.
activestring''
The id of the currently active section. Reflects to an attribute and updates automatically as the user scrolls.
offsetnumber80
Pixel distance from the top of the viewport at which a section counts as current. Increase it to account for taller sticky headers.
progress'none' | 'ring' | 'read' | 'both''none'
How the reader's position through the document is shown. ring draws a progress arc beside the heading; read recedes the entries already scrolled past; both does each. Defaults to none, and an unrecognized value lands there too.

Events

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

See Also