Patterns
Controlled Virtual Index
When to use:
- the logical page index should stay in sync with external UI such as numeric controls
Composition notes:
- drive both the external control and the scroller from the same index state
- let
onScrollSnapChangingoronScrollSnapChangeupdate that state
Trade-offs:
- explicit synchronization
- more moving parts than an uncontrolled scroller
import {
Button,
Icon,
IconButton,
IndexedSnapScroller,
IndexedSnapScrollerContent,
Text,
useIndexedSnapScrollerContext,
type IndexedSnapScrollerApiRef,
} from '@vega-ui/react';
import { ChevronLeft, ChevronRight } from '@vega-ui/icons';
import { useRef, useState } from 'react';Virtual Timeline Window
When to use:
- the visible page set should shift as users move forward or backward
Composition notes:
- tune
size,shift, andstart - keep the page content resilient to changing logical indexes
Trade-offs:
- scalable
- harder to reason about than a fixed page list
import {
IndexedSnapScroller,
IndexedSnapScrollerContent,
Text,
useIndexedSnapScrollerContext,
} from '@vega-ui/react';
import { useCallback, useEffect, useRef, useState } from 'react';
const today = new Date();
const dayFormat = new Intl.DateTimeFormat('en-US', { weekday: 'long', month: 'short', day: 'numeric' });
const moneyFormat = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
Low-Level Calendar Or Timeline Paging
When to use:
- another subsystem needs virtual page indexing but not a domain-specific wrapper yet
Composition notes:
- keep domain logic outside the scroller
- use the exposed index context inside content rendering
Trade-offs:
- reusable foundation
- easy to over-abstract if a higher-level wrapper already exists
import {
IndexedSnapScroller,
IndexedSnapScrollerContent,
Text,
useIndexedSnapScrollerContext,
} from '@vega-ui/react';
import type { CSSProperties } from 'react';
const today = new Date();
const daysSinceMonday = (today.getDay() + 6) % 7;
const weekdayFormat = new Intl.DateTimeFormat('en-US', { weekday: 'short' });
const weekFormat = new Intl.DateTimeFormat('en-US', { month: 'long', day: 'numeric' });Comparison
Quick Decision Rule
Use IndexedSnapScroller when paging should be driven by a logical, potentially unbounded index. Use SnapScroller when the set of snapped pages is already stable and explicit.
IndexedSnapScroller vs SnapScroller
- Use
IndexedSnapScrollerfor shifting logical windows. - Use
SnapScrollerfor direct keyed pages.
IndexedSnapScroller vs DayPickerScroller / YearPickerScroller
- Use
IndexedSnapScrolleras a low-level indexed paging primitive. - Use the picker scrollers when the domain is already calendar paging.
Choose This Component When
- content is best understood as a virtual index sequence
- the page window should shift as users approach boundaries
Do Not Choose This Component When
- a fixed set of pages is already enough
- calendar-specific paging wrappers are more appropriate
Troubleshooting
The Visible Page Jumps After Reaching The Edge
Symptom
The scroller reaches a boundary and the visible content seems to jump.
Likely Cause
The virtual window shifted and the scroll position was not preserved as expected.
How To Verify
- inspect
preserveScroll - watch whether the boundary offset triggers a window reset or append/prepend flow
Fix
Keep preserveScroll enabled when preserving the current snap is the intended experience.
Controlled index And Visible Content Drift Apart
Symptom
The parent says one index is active, but the visible page content suggests another.
Likely Cause
Controlled index updates and internal window resets are not coordinated.
How To Verify
- log the controlled
index - compare it with the committed or pending snap index
Fix
Use one clear source of truth and let the parent react to snap callbacks consistently.
Page State Leaks Across Different Logical Indexes
Symptom
Content appears to reuse stale state as the virtual index changes.
Likely Cause
The content template assumed fixed identity instead of per-index identity.
How To Verify
- inspect child keys and stateful child logic inside the content template
Fix
Make per-index state explicit and avoid assuming one physical DOM page equals one logical page forever.