Styling a SectionList in React Native
The easiest way to apply styles to sections in a SectionList.
I’m currently building Myles Wellbeing, an app which rewards employees for living healthy lifestyles. One of the screens in the Myles Wellbeing app displays your activity ‘history’ which breaks down the activities you’ve tracked each day. I started building this screen in React Native using a SectionList and I found it surprisingly difficult to create sections with rounded corners. Here’s what I wanted it to look like:
What Is a SectionList?
According to the React Native docs, a SectionList is a “performant interface for rendering sectioned lists”. Most importantly, it gives us the ability to render a separator, header and footer in between groups of items.
When you search how to style the sections in a SectionList, some websites suggest rendering a FlatList for each section, instead of using a SectionList. Do not do this as it will negate the benefits of a virtualised list.
Why Is It Difficult To Style a SectionList?
It is difficult to style the sections of a SectionList because there are no sections being rendered. Behind the scenes, the SectionList is rendering a list of items and inserting section headers, footers and separators in between groups of items. There are no React Native components wrapping the sections, which is why there is no sectionStyle
or renderSection
prop for us to use.
Conceptually, it is rendered something like this:
return (
<>
<SectionHeader /> {/* Inserted before section */}
<Item />
<ItemSeparator />
<Item />
<ItemSeparator />
<Item />
<ItemSeparator />
<Item />
<SectionFooter /> {/* Inserted after section */}
<SectionSeparator /> {/* Inserted in between sections */}
</>
);
return (
<>
<SectionHeader /> {/* Inserted before section */}
<Item />
<ItemSeparator />
<Item />
<ItemSeparator />
<Item />
<ItemSeparator />
<Item />
<SectionFooter /> {/* Inserted after section */}
<SectionSeparator /> {/* Inserted in between sections */}
</>
);
How To Style the SectionList
The key to styling a SectionList is to style the first and last items of each section differently from the other items. Let’s begin by styling all items the same and then we’ll add the additional styles for the first and last item.
import { SectionList, StyleSheet, Text, View } from "react-native";
const styles = StyleSheet.create({
item: {
backgroundColor: "#eeeeee",
borderBottomColor: "#000000",
borderBottomWidth: 1,
padding: 8,
},
header: {
marginVertical: 8,
},
});
function renderItem({ item }) {
return (
<View style={styles.item}>
<Text>{item}</Text>
</View>
);
}
function renderSectionHeader({ section: { title } }) {
return (
<View style={styles.item}>
<Text>{title}</Text>
</View>
);
}
export function StyledSectionList({ sections }) {
return (
<SectionList
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
sections={sections}
stickySectionHeadersEnabled={false}
/>
);
}
import { SectionList, StyleSheet, Text, View } from "react-native";
const styles = StyleSheet.create({
item: {
backgroundColor: "#eeeeee",
borderBottomColor: "#000000",
borderBottomWidth: 1,
padding: 8,
},
header: {
marginVertical: 8,
},
});
function renderItem({ item }) {
return (
<View style={styles.item}>
<Text>{item}</Text>
</View>
);
}
function renderSectionHeader({ section: { title } }) {
return (
<View style={styles.item}>
<Text>{title}</Text>
</View>
);
}
export function StyledSectionList({ sections }) {
return (
<SectionList
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
sections={sections}
stickySectionHeadersEnabled={false}
/>
);
}
Every item looks the same with square corners and a black border on the bottom.
Styling the First and Last Item Differently
Now let’s add the styles for the first and last item. We can do this by checking the index
passed to the renderItem
function:
- The first item will have
index === 0
- The last item will have
index === section.data.length - 1
The section
is also passed to the renderItem
function and contains all the information about the current section.
import { SectionList, StyleSheet, Text, View } from "react-native";
const styles = StyleSheet.create({
item: {
backgroundColor: "#eeeeee",
borderBottomColor: "#000000",
borderBottomWidth: 1,
padding: 8,
},
itemFirst: {
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
},
itemLast: {
borderBottomLeftRadius: 8,
borderBottomRightRadius: 8,
borderBottomWidth: 0,
},
header: {
marginVertical: 8,
},
});
function renderItem({ item, index, section }) {
return (
<View
style={[
styles.item,
index === 0 && styles.itemFirst,
index === section.data.length - 1 && styles.itemLast,
]}
>
<Text>{item}</Text>
</View>
);
}
function renderSectionHeader({ section: { title } }) {
return (
<View style={styles.item}>
<Text>{title}</Text>
</View>
);
}
export function StyledSectionList({ sections }) {
return (
<SectionList
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
sections={sections}
stickySectionHeadersEnabled={false}
/>
);
}
import { SectionList, StyleSheet, Text, View } from "react-native";
const styles = StyleSheet.create({
item: {
backgroundColor: "#eeeeee",
borderBottomColor: "#000000",
borderBottomWidth: 1,
padding: 8,
},
itemFirst: {
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
},
itemLast: {
borderBottomLeftRadius: 8,
borderBottomRightRadius: 8,
borderBottomWidth: 0,
},
header: {
marginVertical: 8,
},
});
function renderItem({ item, index, section }) {
return (
<View
style={[
styles.item,
index === 0 && styles.itemFirst,
index === section.data.length - 1 && styles.itemLast,
]}
>
<Text>{item}</Text>
</View>
);
}
function renderSectionHeader({ section: { title } }) {
return (
<View style={styles.item}>
<Text>{title}</Text>
</View>
);
}
export function StyledSectionList({ sections }) {
return (
<SectionList
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
sections={sections}
stickySectionHeadersEnabled={false}
/>
);
}
That’s the easiest way I’ve found of styling a SectionList. Thanks for reading!