ScrollView
A SwiftUI ScrollView component for scrollable content.
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
Expo UI ScrollView matches the official SwiftUI ScrollView API and provides a scrollable container for its children.
Installation
- npx expo install @expo/uiIf you are installing this in an existing React Native app, make sure to install expo in your project.
Usage
Basic vertical scroll view
A simple vertically scrollable list of text items.
import { Host, ScrollView, VStack, Text } from '@expo/ui/swift-ui'; import { padding } from '@expo/ui/swift-ui/modifiers'; export default function ScrollViewVerticalExample() { return ( <Host style={{ flex: 1 }}> <ScrollView> <VStack spacing={8}> {Array.from({ length: 30 }, (_, i) => ( <Text key={i} modifiers={[padding({ horizontal: 16 })]}> {`Item ${i + 1}`} </Text> ))} </VStack> </ScrollView> </Host> ); }
Horizontal scroll view
Use the axes prop to scroll horizontally.
import { Host, ScrollView, HStack, RoundedRectangle } from '@expo/ui/swift-ui'; import { frame, foregroundStyle } from '@expo/ui/swift-ui/modifiers'; export default function ScrollViewHorizontalExample() { return ( <Host style={{ flex: 1 }}> <ScrollView axes="horizontal"> <HStack spacing={8}> {Array.from({ length: 20 }, (_, i) => ( <RoundedRectangle key={i} cornerRadius={12} modifiers={[ frame({ width: 100, height: 100 }), foregroundStyle(`hsl(${i * 18}, 70%, 50%)`), ]} /> ))} </HStack> </ScrollView> </Host> ); }
Hidden scroll indicators
Set showsIndicators to false to hide the scroll bars.
import { Host, ScrollView, VStack, Text } from '@expo/ui/swift-ui'; export default function ScrollViewHiddenIndicatorsExample() { return ( <Host style={{ flex: 1 }}> <ScrollView showsIndicators={false}> <VStack spacing={8}> {Array.from({ length: 30 }, (_, i) => ( <Text key={i}>{`Item ${i + 1}`}</Text> ))} </VStack> </ScrollView> </Host> ); }
Shared scroll position
Requires iOS 17 or later. On older versions, the modifier is a no-op.
Track the leading scroll target id from JavaScript and scroll to a target by writing to the state. Mark each scroll target with the id modifier, wrap the content container in scrollTargetLayout, and apply the scrollPosition modifier to the ScrollView. The optional onChange callback fires on the JS thread when the leading target changes.
The scrollPosition modifier also works on other scrollable containers like LazyVStack and LazyHStack.
Writes tostate.valuemust run on the UI runtime. Wrap the write inscheduleOnUIfromreact-native-worklets, or call them from inside a'worklet'function. Writes from the JS runtime trip Main Thread Checker, Xcode's runtime tool that flags UIKit calls made from a background thread.
import { Button, Host, ScrollView, Text, VStack, useNativeState } from '@expo/ui/swift-ui'; import { id, padding, scrollPosition, scrollTargetLayout } from '@expo/ui/swift-ui/modifiers'; import { scheduleOnUI } from 'react-native-worklets'; export default function ScrollViewSharedPositionExample() { const activeID = useNativeState<string | null>(null); return ( <Host style={{ flex: 1 }}> <VStack spacing={12}> <ScrollView modifiers={[ scrollPosition(activeID, { onChange: newID => { console.log('[JS thread] leading target:', newID); }, }), ]}> <VStack modifiers={[scrollTargetLayout()]}> {Array.from({ length: 30 }, (_, i) => ( <Text key={`item-${i}`} modifiers={[id(`item-${i}`), padding({ horizontal: 16, vertical: 12 })]}> {`Item ${i}`} </Text> ))} </VStack> </ScrollView> <Button label="Scroll to item 10 from worklet" onPress={() => { scheduleOnUI(() => { 'worklet'; activeID.value = 'item-10'; }); }} /> </VStack> </Host> ); }
API
import { ScrollView } from '@expo/ui/swift-ui';
Component
Type: React.Element<ScrollViewProps>