React Native’s ScrollView component is a generic container that can contain multiple elements — Views, Texts, Pressables, and even another ScrollView. After putting all those elements inside the ScrollView component, you can use it to scroll through them vertically (the default) or horizontally (by adding it as a prop).
We can see scrolled components in almost every app available on the App Store and Google Play. Today, I’ll explain some common mistakes when using ScrollView in React Native and how to avoid them, plus a few tips and tricks to help provide the best user experience possible.
The first and most common mistake of using ScrollView is not knowing when to use it. There are two common List components in React Native: ScrollView and FlatList.
To determine which one to use, we only have to remember one thing: ScrollView works best to display a small amount of elements with a limited size because all of ScrollView’s children components are rendered at once — even if they’re not currently visible on-screen.
This is why if you have a lot of elements inside your ScrollView and some of them are, for example, taller, portrait-style pictures, ScrollView’s performance may be a bit laggy and unpleasant for the user.
Whenever you’re fetching data from an API in the form of lists, for example, the best way to display them in your app would be with the FlatList component, which is implemented differently. Because FlatList only renders elements that are currently showing on the screen — not all the elements at once — it is capable of displaying long lists in a more performant way.
FlatList exposes to us a long list of props that are designed for the best UX and performance of rendering long data lists, including:
removeClippedSubviews
– A Boolean that, when enabled (it’s false
by default), detaches views that are outside the viewport from the native view hierarchy, which reduces time spent on the main thread, leading to reduced risk of dropped framesinitialNumToRender
– This is the initial amount of items to be rendered into the FlatList. The best practice is to define the precise amount of items that would cover the viewport for every device, which could be a performance boost for the initial rendering of the component. Setting this number too low may cause blank areasThere are a few more great tips on how to improve FlatList performance, which have been very well explained in the docs here. I hope by reading the paragraph above I helped you understand when to use which component.
Now that we know when to use the ScrollView component, let’s take a look at how to use it. Beginners often waste a lot of time figuring out how to properly style the ScrollView because it has two styling props: style
and contentContainerStyle
. Here’s a short explanation of those props:
style
prop is used for the styling of the ScrollView parent element, which we can think of as a simple, non-scrollable View. We’re setting the size of the ScrollView element on the window viewport and its relative position to sibling elements. This parent container cannot exceed viewport’s height or widthcontentContainerStyle
prop is a scrollable container inside the parent ScrollView I described above. It’s the moving part of the ScrollView, and this is where we’re applying styles that allow us to align the items inside, add padding, etc.Here’s a live example you can test on snack.expo.io:
So now that we know when to use ScrollView and how to style it, I’ll explain some of the common props that may cause some confusion and lead to bugs.
When working with ScrollView, we often need to track the scroll position. To do so correctly, we should use onScroll
props. This event fires maximally once per frame during scrolling. A single scroll event is an object that looks like this:
{ nativeEvent: { contentInset: {bottom, left, right, top}, contentOffset: {x, y}, contentSize: {height, width}, layoutMeasurement: {height, width}, zoomScale } }
In order to use those values correctly, we have to know what each of those properties does:
contentInset
– This is the margin of distance from the edges of the ScrollView to its content; the default object value is {top: 0, left: 0, bottom: 0, right: 0}
contentOffset
– This value is the distance that the user has already scrolled from the beginning, most often used when we want to track the scrolled value. If it’s a horizontal ScrollView component, we’re using contentOffset.x
; if it’s vertical, we’re using contentOffset.y
contentSize
– We use this prop to get the height
and width
of the content inside the ScrollView. It’s often used together with layoutMeasurement
and contentOffset
— for example, to determine whether the user has scrolled to the end of the content. We have to be especially careful when using this prop because it is not available on Android for performance reasonslayoutMeasurement
– This is the height
and width
of the viewportzoomScale
– The current scale value of the ScrollView’s content. When ScrollView contains only one Image component, we can use it together with the maximumZoomScale
and minimumZoomScale
props to zoom in on the ImageCorrectly using onScroll
and tracking scroll position may be a tricky task due to performance reasons. This is why it’s always important to remember how many necessary operations we’re calling with a single scroll event.
To have better control of the scroll event, we use a scrollEventThrottle
prop, which controls how often the scroll event will be fired while the user is scrolling (by time interval in milliseconds). A lower amount can lead to better accuracy for tracking the scroll value position (contentOffset
), but it may often lead to performance issues.
The difference between values 1–16 will not be noticeable for the eye because the JS run loop is synchronized to the screen refresh rate (16 is the recommended number here in most cases). Setting a higher number results in less code sent across the React Native bridge, which improves performance.
Last but not least, I wanted to talk about nesting a ScrollView component in another ScrollView component. We may sometimes want this kind of composition when, for example, implementing a mix of horizontal and vertical elements.
By default, nesting ScrollViews is automatically enabled on iOS, but in order to have it on Android, we have to set the nestedScrollEnabled
props to true
and also remember that our Android API must be on level 21+ (the default in React Native v0.63 is 24).
Although there are many more interesting props inside the ScrollView component that allow us to create tons of interesting user experiences, I think I’ve emphasized the most common mistakes and important use cases of the ScrollView component based on my experience.
I hope I’ve explained them in a way that will help you use this component a bit more easily. If you have any other issues with the use of ScrollView component, feel free to address them in the comment section — I’ll keep an eye on it, and I’ll answer all the questions you may have.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
9 Replies to "Common bugs in React Native ScrollView and how to fix them"
in the example code, the height attribute on the scroll container does not work
Hey there- you’re right, thank you for pointing that out – in order to have a specific height on a ScrollIView component we have to wrap it up in View wrapper and set the height there.
Do you know what happens with a flex layout inside scroll view?
I am trying to configure table grid layout in react native which could be scrollable horizontally and vertically:
https://stackoverflow.com/questions/65626761/horizontally-and-vertically-scrollable-layout-in-react-native
The problem is that once I add a scroll view, flex:1 stops working
Doing complex grid layouts in React Native is a little bit tricky so you’d be better off using some kind of 3rd party library like https://github.com/saleel/react-native-super-grid.
thank you so much for the explanation, especially the difference between “style” and “contentContainerStyle”, which was the part that helps me to fix my problem.
I’m really glad that I could help you!
Hello. Thanks for sharing your knowledge.
In Android it seems that paddingBottom and marginBottom do not work correctly, you have to set paddingBottom on contentContainerStyle to give a little space at the bottom of the ScrollView. Is it a correct behavior or is there a bug?
Hello, Yes this is a correct behaviour, in my current experience ScrollView is the one component that has the highest amount of differences on Android vs iOS.
I am facing problem in nested horizontal scrolling
its not working using nestedScrollEnabled={true}