title: ScrollView: scroll position & visibility tracking description: scrollPosition(id:anchor:) two-way binds the leading visible item's id to JS state on plain ScrollView (no ScrollViewReader needed). onScrollTargetVisibilityChange (iOS 18+) reports the full visible-id set as you scroll. Children mark themselves with key={...} (mapped to SwiftUI .id()) and the layout container needs scrollTargetLayout.
The ScrollView component displays its content within a scrollable region. As the user performs scroll gestures, the visible portion of the content is updated accordingly. You can scroll vertically, horizontally, or in both directions using the axes prop.
Type
Overview
- Scroll direction is controlled by the
axesproperty. - Contents are placed inside children, typically using layouts like
<VStack>or<HStack>. - Zooming is not supported.
Default Behavior
- The default scroll axis is vertical.
- Scroll indicators are shown based on platform conventions unless configured via modifiers.
Example
ScrollView Modifiers
You can apply the following view modifiers to configure scroll-related behavior.
scrollIndicator
Controls the visibility of scroll indicators.
Type
ScrollScrollIndicatorVisibility options:
"automatic": Follows platform default behavior."visible": Indicators appear but may auto-hide based on OS behavior."hidden": Hidden unless overridden by system behavior."never": Never show indicators.
Example
With axis-specific visibility:
scrollDisabled
Enables or disables scrolling behavior entirely.
Type
Example
scrollClipDisabled
Controls whether the scroll view clips content that extends beyond its bounds.
Type
Example
scrollDismissesKeyboard
Determines how the scroll interaction affects the software keyboard.
Type
Options
"automatic": Default behavior based on context."immediately": Dismiss keyboard as soon as scrolling starts."interactively": Allow user to drag to dismiss keyboard."never": Scrolling will not dismiss the keyboard.
Example
defaultScrollAnchor
Defines which point in the content should be visible initially or stay anchored when content size changes.
Type
KeywordPoint values
"top","bottom","leading","trailing","center","topLeading","bottomTrailing"etc.
Example
AxisSet
Defines the scrollable directions for a scroll view.
Type
Usage
scrollTargetLayout
Applies this modifier to layout containers such as LazyHStack, LazyVStack, HStack, or VStack that represent the main repeating content inside a ScrollView.
Type
Usage
When set to true, this modifier designates the associated layout container as a scroll target region within the ScrollView. It allows the scroll behavior system to determine how scrolling should align to elements within the container.
scrollTargetBehavior
Defines how scrollable views behave when aligning content to scroll targets.
Type
Description of Variants
"paging": Scrolls one page at a time, aligned to the container’s dimensions."viewAligned": Scrolls to align views directly, based on view frames."viewAlignedLimitAutomatic": Limits scrolling in compact horizontal size classes, but allows full scrolling otherwise."viewAlignedLimitAlways": Always restricts scrolling to a limited number of items."viewAlignedLimitNever": Allows unrestricted scrolling without view-based limitations."viewAlignedLimitAlwaysByFew"(iOS 18.0+): Limits scrolling to a small number of views per gesture, automatically determined."viewAlignedLimitAlwaysByOne"(iOS 18.0+): Restricts each scroll gesture to advance exactly one view at a time.
Description
This modifier configures the scroll behavior, such as paging and alignment strategy, for views within a scrollable container.
scrollPosition
Two-way binds the id of the leading visible item in a ScrollView to JS state. Mirrors SwiftUI's .scrollPosition(id:anchor:) — no ScrollViewReader wrapper required.
Type
Setup
- The container directly under the
ScrollView(typicallyLazyVStack/LazyHStack/VStack) needsscrollTargetLayout. - Each child you want to be a scroll target needs a
key="..."prop — the bridge maps it to SwiftUI's.id(). - Bind
scrollPositionto a state —Observableform or{ value, onChanged }form.
Example
idmay bestringornumber. Pick the type when initialising the state and stick with it — the bridge dispatches on the runtime type.- Setting the state to
nulllets SwiftUI manage the scroll position; setting it to a known id scrolls that item to the anchor. anchoris aUnitPoint: a string keyword ("top"/"center"/"leading"/ ...) or{ x, y }.
Pitfalls
- Forgetting
scrollTargetLayout. Without it, SwiftUI doesn't know which subview is the "current" scroll target — the binding silently does nothing. - Mixing id types. A
Observable<number>won't bind against a child whosekeywas rendered as a string. Keep both sides consistent. - Type changes mid-flight. Initialise the observable with a real value (e.g.
useState<string|null>("first")) so the bridge can detect the type at modifier time. A purely-null-initial observable defaults to the string path. - ScrollViewReader vs scrollPosition. Don't bind both to the same scroll view — the imperative
scrollTo(id:)and declarativescrollPositionwill fight each other. Pick one.
onScrollTargetVisibilityChange
iOS 18+. Reports the set of currently-visible scroll target ids whenever it changes (filtered by threshold). Mirrors SwiftUI's .onScrollTargetVisibilityChange(idType:threshold:_:).
Type
Setup
Same as scrollPosition:
- The layout container needs
scrollTargetLayout. - Children must be marked with
key="..."orkey={123}. idTypemust match the runtime type of the keys. The SwiftUI API is generic, and the bridge has to dispatch statically at modifier-creation time — there's no way to recover the ID type from[AnyHashable]at runtime. Use"string"for string keys,"number"for number keys.
Example
Pitfalls
- iOS 17 fallback. On iOS 17 the bridge logs an
API deprecatedwarning and skips the modifier — content passes through. Other modifiers are unaffected. thresholdsemantics.0.5= the view must be at least 50% within the viewport to count as visible.0= any pixel triggers;1= the entire view must be visible.- Callback frequency. During scrolling the callback is invoked on the main thread inline (no throttling). A list with ~30 items where ~5 are visible is fine; for very dense lists with rapid scrolling, keep the callback body cheap.
- Compatible with
scrollPosition. They serve different purposes —scrollPositiongives you the leading id,onScrollTargetVisibilityChangegives you the entire visible set. Using both on the same scroll view is safe.
scrollContentBackground
Specifies the visibility of the background for scrollable views, such as ScrollView, within the current view context.
Type
Description
This modifier controls whether the default background behind scrollable content (typically a system-provided background) is shown, hidden, or determined automatically based on system behavior.
It is commonly used when customizing the appearance of scrollable views or when layering custom backgrounds behind scroll content.
Visibility Options
-
'automatic'The system decides whether the background should be visible based on the current context and platform conventions. -
'hidden'Hides the scroll view’s default background, allowing custom background layers or transparent effects. -
'visible'Forces the default scroll content background to be shown, even if a custom background is present.
Example: Hiding Scroll Background
This example removes the default background from the scroll view, making it fully transparent or allowing underlying views to show through.
