Stop Scrolling at Regular Intervals in React Native
Published On: 2024-06-14
Posted By: Harish

Generally, when content is scrolled, it scrolls till the momentum of the scrolling speed lasts. In some scenarios, we need to stop scrolling at regular intervals irrespective of the speed of the scroll.
In those situations, we can use snapToInterval prop to stop scroll at regular intervals of a value. This prop needs to be used with disableIntervalMomentum prop to stop the scroll momentum for intervals.
Let's see how it works with an example.
Create A New Project
Create a new react-native project by using npx. Check documentation for creating a new react native project.
npx react-native@latest init ScrollViewRN
Example Implementation
We will create a horizontal scrollview with few color blocks as a carousel and when scrolled, we will use the above props to stop at the next or previous color block.
Import and add ScrollView
with some color blocks and horizontal orientation. Give a fixed width to color blocks. For now, I'm giving 200
as width.
//App.tsx
...
import { View, ScrollView } from 'react-native';
...
<ScrollView
contentContainerStyle={{ alignSelf: 'flex-start' }}
horizontal
>
{
colors
.map((color: string) => {
return (
<View
key={color}
style={[
styles.view,
{
backgroundColor: color
}
]}
>
</View>
)
})
}
</ScrollView>
...
If we run the app,
#for Android
npx react-native run-android
#for ios
npx react-native run-ios
We will see some scrollable horizontal color blocks and it will have a smooth scroll.

Now add, snapToInterval
prop with a value. Multiples of this value will be the stopping point for each scroll.
Above, we have given 200 as a width, so we'll stop scrolling at regular intervals of 200.
So, add snapToInterval={200}
. We also need to add disableIntervalMomentum={true}
to work correctly.
...
<ScrollView
...
disableIntervalMomentum={true}
snapToInterval={200}
>
...
</ScrollView>
...
Now, try to scroll as fast as you can, you will observe that the scrolling will stop at multiples of 200. This scroll can be viewed as x-axis and the values as x-coordinates.
No matter how fast you scroll, they will decelerate and stop at that interval. We can also use decelerationRate prop if you want.

For better understanding, make the scrollview width as the width of each color block.
We can get the scrollview's width with onLayout callback which returns a size event on load.
So, add onLayout callback, get the scrollview width and apply it to the color block.
...
const [size, setSize] = useState<LayoutRectangle>();
...
<ScrollView
...
snapToInterval={size?.width}
onLayout={e => setSize(e.nativeEvent.layout)}
>
...
</ScrollView>
...
If we re-run the app, we can see that the color block fits perfectly to the width of the scrollview.
Now try to scroll as fast as you can. You will see that no matter how fast you scroll, it stops at the next color block and vice versa.

Here, scrolling stops because the interval gets snapped to the edge. You can find more about snapping in snapToOffsets post.
Complete code of our example,
//App.tsx
import React, { useState } from "react";
import {
Text,
StyleSheet,
SafeAreaView,
StatusBar,
View,
ScrollView,
LayoutRectangle,
} from "react-native";
const colors = [
'orange',
'green',
'blue',
'maroon',
'violet',
'darkorange',
'gold',
'darkgreen',
'aquamarine',
'cadetblue'
];
export default function App() {
const [size, setSize] = useState<LayoutRectangle>();
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
<StatusBar
barStyle="dark-content"
/>
<View style={styles.container}>
<Text style={styles.text}>
ifelsething.com
</Text>
<Text style={styles.text}>
stop scrolling at regular intervals
</Text>
<ScrollView
contentContainerStyle={{ alignSelf: 'flex-start' }}
horizontal
disableIntervalMomentum={true}
snapToInterval={size?.width}
onLayout={e => setSize(e.nativeEvent.layout)}
>
{
colors
.map((color: string) => {
return (
<View
key={string}
style={[
styles.view,
{
backgroundColor: color,
width: size?.width || 200
}
]}
>
</View>
)
})
}
</ScrollView>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
margin: 10,
gap: 20
},
text: {
fontSize: 15,
color: 'black',
fontStyle: 'italic'
},
view: {
height: 200,
borderRadius: 10,
}
});