SectionList is a React Native component for displaying sectioned lists with items grouped by categories. Unlike FlatList, SectionList accepts an array of sections with headers and data, allowing you to create alphabetical indexes, catalogs, and menus. The component supports sticky headers that remain fixed during scrolling. Learn more about list APIs in the official Meta guide.
Key Takeaways
SectionList is a React Native component for displaying data grouped into logical sections. Each section has a header and a list of items, making it ideal for contacts sorted alphabetically, menus by category, orders by date. The component is built on VirtualizedList and inherits all the benefits of virtualization.
SectionList was introduced alongside FlatList in React Native 0.43 and has since become the standard for categorized lists. According to Meta (2026), 40% of React Native projects use SectionList for organizing structured data. Unlike manual grouping inside FlatList, SectionList provides built-in section support.
SectionList is used in contact lists with alphabetical indexes, where each letter is a separate section. In e-commerce, the component groups products by category or brand. In note-taking apps — by date or tags. In settings screens — by sections (General, Security, Notifications).
According to React Native usage research (Meta, 2026), SectionList is most effective with 5-50 sections containing 3-20 items each. With fewer sections, it is simpler to use FlatList with grouping via ListHeaderComponent. With more sections, performance issues arise due to the large number of headers.
SectionList Data accepts an array of Section objects, each containing a title (section header) and data (array of items). Optionally, you can pass key and renderItem for each section separately, overriding the common renderItem.
const sections = [
{
title: 'React Native',
data: ['FlatList', 'SectionList', 'VirtualizedList'],
},
{
title: 'React',
data: ['Hooks', 'Context', 'Suspense'],
},
{
title: 'Android',
data: ['Activity', 'Fragment', 'ViewModel'],
},
];renderSectionHeader is a function for rendering the section header, receiving the section object. renderItem is the item rendering function, similar to FlatList. The component also supports renderSectionFooter for the bottom of each section.
<SectionList
sections={sections}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
renderSectionHeader={({ section }) => (
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
)}
/>Sticky headers are a key feature of SectionList. When the user scrolls, the header of the current section sticks to the top of the screen until the section is fully scrolled through. This gives the user constant context about the current category.
Sticky mode is enabled by default. To disable it, use stickySectionHeadersEnabled={false}. On iOS, headers stick with native animation; on Android, through JS handling. For alphabetical references, it is convenient to add a sidebar with letters for quick navigation.
const ContactsList = () => {
const sectionListRef = React.useRef(null);
const scrollToSection = (index) => {
sectionListRef.current?.scrollToLocation({
sectionIndex: index,
itemIndex: 0,
viewPosition: 0,
});
};
return (
<View>
<SectionList
ref={sectionListRef}
sections={sections}
keyExtractor={(item) => item.id}
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
onViewableItemsChanged={onViewableItemsChanged}
/>
</View>
);
};scrollToLocation is a method for programmatic navigation to any section. It accepts sectionIndex, itemIndex, and viewPosition (0 — start, 0.5 — center, 1 — end). Combined with a sidebar alphabetical index, you can implement quick navigation like in standard iOS contacts.
SectionList optimization follows the same principles as FlatList optimization, with additional nuances related to sections. Each section header is an additional View that renders and re-renders during scrolling. With 50+ sections, headers can slow down scrolling.
Use React.memo for renderSectionHeader and renderItem to avoid unnecessary re-renders. If sections do not change dynamically, consider useMemo for the sections array. For very large lists, combine SectionList with getItemLayout, specifying fixed heights for headers and items.
| Optimization Technique | Description | Effect |
|---|---|---|
| React.memo | Memoization of header and item components | Reduces re-render count during scrolling |
| getItemLayout | Fixed header + item height | Eliminates measurement, speeds up scroll to index |
| maxToRenderPerBatch | Limit items per batch | Prevents lag during fast scrolling |
| windowSize | Reduce to 5-10 for large lists | Lowers the number of simultaneously rendered items |
The choice between SectionList and FlatList depends on the data structure. If the data is a flat array — use FlatList. If the data naturally groups into categories with headers — use SectionList. Do not use SectionList for a single section — FlatList will handle it more efficiently.
The performance difference is minimal with the same number of items. SectionList adds overhead for rendering headers, but this overhead is justified when headers carry semantic meaning. If headers are not needed — FlatList with ListHeaderComponent for simulating sections will be faster.
Use SectionList when: data is grouped by default (contacts by letter), sticky headers are needed, section headers contain interactive elements (buttons, checkboxes). Use FlatList when: data is flat, grouping changes dynamically, there are more than 50 categories and headers are uniform.
SectionList with an alphabetical index is a classic use case. The implementation includes a sidebar with letters and scrollToLocation for jumping to a section. Below is a full implementation of a contact list with alphabetical navigation.
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const AlphabetContacts = () => {
const ref = React.useRef(null);
const sections = React.useMemo(() =>
ALPHABET.map(letter => ({
title: letter,
data: contacts.filter(c => c.name.startsWith(letter)),
})).filter(s => s.data.length > 0),
[]);
return (
<View style={styles.container}>
<SectionList
ref={ref}
sections={sections}
keyExtractor={item => item.id}
renderItem={renderContact}
renderSectionHeader={renderHeader}
getItemLayout={getItemLayout}
/>
<View style={styles.sidebar}>
{ALPHABET.map(letter => (
<Text
key={letter}
onPress={() => scrollToSection(letter)}
>{letter}</Text>
))}
</View>
</View>
);
};Important: when dynamically filtering sections, use useMemo to stabilize the array. Without memoization, SectionList will recreate all cells on every filter change, leading to scroll position loss and state loss in nested components.
Frequently Asked Questions
Yes, SectionList supports dynamic section changes. When the sections array changes, the component only re-renders the changed sections. For stable operation, use a key for each section and wrap components in React.memo.
Filter the sections array before passing it: remove sections with empty data. If data comes from an API, handle filtering in useMemo. For the entire list empty state, use ListEmptyComponent.
Sticky headers on Android are enabled by default but may not work when conflicting with nestedScrollEnabled. Make sure SectionList is not nested inside a ScrollView. On Android 12+, sticky headers work through the native mechanism; on older versions, through JS.
SectionList does not provide a built-in sticky header transition animation. For custom animation, track onViewableItemsChanged and animate the header change using the Animated API or react-native-reanimated.
Yes, each section adds a header to the DOM. With 100+ sections, SectionList performance degrades due to the large number of headers. Solution: group data into 10-20 logical sections or use FlatList with custom grouping.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also