How to Build a Slider in React Native Using FlatList
When implementing a slider in React Native, many developers instinctively turn to external libraries, assuming that creating a slider from scratch is a complex task. However, what may seem like a daunting challenge is actually much simpler to accomplish in React Native using its built-in components—often more straightforward than implementing a similar feature on the web.
So, how can you build a slider without relying on third-party libraries?
In this tutorial, I'll show you how to create a fully functional slider in React Native using just FlatList
with minimal code. It's an easy and effective approach that leverages React Native's native components to achieve smooth, efficient sliders.
We are going to create this style of slider
Creating the item component
import { View, Text, StyleSheet, Image } from "react-native";
interface OnboardingCardProps {
imageUrl: string;
title: string;
description: string;
width: number;
}
const OnboardingCard = ({
imageUrl,
title,
description,
width,
}: OnboardingCardProps) => {
return (
<View style={[styles.container, { width }]}>
<Image source={{ uri: imageUrl }} style={styles.image} />
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{description}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
backgroundColor: "#fff",
},
image: {
width: 150,
height: 150,
resizeMode: "contain",
marginBottom: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#000",
textAlign: "center",
marginBottom: 10,
},
subtitle: {
fontSize: 16,
color: "#666",
textAlign: "center",
paddingHorizontal: 20,
},
});
export default OnboardingCard;
Creating the slider
import { Dimensions, FlatList, StyleSheet } from "react-native";
import { onboardingSteps } from "data/onboarding";
import OnboardingCard from "components/onboarding/OnboardingCard";
const screenWidth = Math.round(Dimensions.get("window").width);
const Onboarding = () => {
return (
<FlatList
style={styles.slider}
horizontal
data={onboardingSteps}
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.sliderItemsWrapper}
pagingEnabled
renderItem={({ item }) => (
<OnboardingCard
width={screenWidth}
title={t(item.title)}
description={t(item.description)}
image={item.image}
/>
)}
/>
);
};
export default Onboarding;
const styles = StyleSheet.create({
viewport: {
flex: 1,
},
wrapper: {
flex: 1,
},
slider: {
flex: 1,
},
sliderItemsWrapper: {
display: "flex",
alignItems: "center",
},
});
Explaining the props used on the FlatList
horizontal
prop allow us to have items aligned horizontallyThe
pagingEnabled
prop is what creates the “snapping” effect in a scrollable view. When this prop is set totrue
, the user can only scroll one full page (or item) at a time, causing the scroll to “snap” to the nearest page when they release their finger. This means that partial views of items won't be left visible; the scroll will always land in such a way that one full item is shown, creating a smooth, page-by-page scrolling experience.Without it, here is how the scroll goes
But with it, we got this
showsHorizontalScrollIndicator
is to hide the scroll indication
FlatList
and its items have the same width.Adding the indicators
Dot component ( the dot item component )
import { StyleSheet, View } from "react-native";
interface DotProps {
active: boolean;
}
const Dot = ({ active }: DotProps) => {
return <View style={[styles.dot, ...(active ? [styles.active] : [])]} />;
};
export default Dot;
const styles = StyleSheet.create({
dot: {
backgroundColor: "#D3BDF2",
borderRadius: 50,
marginHorizontal: 5,
width: 10,
height: 10,
},
active: {
width: 16,
height: 16,
backgroundColor: "#6A3EFC",
},
});
The dots list component
import { StyleSheet, View } from "react-native";
import Dot from "./Dot";
interface DotIndicatorsProps {
itemCount: number;
activeIndex: number;
}
const DotIndicators = ({ activeIndex, itemCount }: DotIndicatorsProps) => {
return (
<View style={styles.container}>
{Array.from({ length: itemCount }).map((_, index) => (
<Dot active={activeIndex === index} />
))}
</View>
);
};
export default DotIndicators;
const styles = StyleSheet.create({
container: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
});
Creating a state for the current item
Storing the current active index into a state and display the dots indicators.
import { Dimensions, FlatList, StyleSheet } from "react-native";
import { onboardingSteps } from "data/onboarding";
import OnboardingCard from "components/onboarding/OnboardingCard";
const screenWidth = Math.round(Dimensions.get("window").width);
const Onboarding = () => {
const [currentIndex, setCurrentIndex] = useState(0);
return (
<>
<FlatList
// ...
viewabilityConfig={{ viewAreaCoveragePercentThreshold: 100 }}
onViewableItemsChanged={({ viewableItems, changed }) => {
const currentIndex = viewableItems.at(0)?.index;
if (currentIndex !== null && currentIndex !== undefined) {
setCurrentIndex(currentIndex);
}
}}
/>
<DotIndicators
itemCount={onboardingSteps.length}
activeIndex={currentIndex}
/>
</>
);
};
The viewabilityConfig.viewAreaCoveragePercentThreshold
prop determines the percentage of an item that must be visible for it to be considered "viewable" within the viewport. By setting this value to 100
, the item will only be considered "viewable" when it is fully visible (i.e., 100% of the item's area is visible on the screen).
This ensures that the current index calculation is more accurate, particularly when the user is scrolling slowly. Without this setting, items that are only partially visible could be incorrectly marked as "viewable," causing the currentIndex
to update prematurely or inaccurately. By enforcing the requirement that an item must be fully visible, you prevent incorrect index changes that can occur when the user is scrolling slowly and only small parts of items are entering or exiting the viewport.
In short, setting the viewAreaCoveragePercentThreshold
to 100%
ensures that the current item index only changes when the item is fully in view, leading to more precise behavior during slow scrolling.
The result
Conclusion
You only need three props to create a slider in React Native without external libraries:
pagingEnabled
: Enables the snap effect for smooth scrolling.onViewableItemsChanged
: Tracks the active item as the user scrolls.viewabilityConfig.viewAreaCoveragePercentThreshold
: Ensures accurate active index calculation by requiring 100% of the item to be visible.
With just these props, you can easily create a slider using React Native's built-in components.
Resources
Subscribe to my newsletter
Read articles from Juste R. Bocovo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Juste R. Bocovo
Juste R. Bocovo
A full-stack JavaScript developer. Using tools like React/Next and Nest to build project that make something better. My slogan is : I help build the tools of tomorrow.