In a React Native SectionList, how does SectionSeparatorComponent differ from ItemSeparatorComponent, and which props do separators receive?
answer
- item separators stay inside a section
- section separators bracket the items
- leading and trailing item and section
- components get props, elements do not
- empty sections get no separators
basics
~20 sIn a React Native SectionList, ItemSeparatorComponent renders between items within a section only, while SectionSeparatorComponent renders before a section's first item and after its last. Both receive highlighted, section and leading/trailing item and section props when passed as components.
solid answer
~50 s`ItemSeparatorComponent` renders **between items of the same section** — never after a section's last item. `SectionSeparatorComponent` renders at the **top and bottom of each section's items**: between the header and the first item, and between the last item and the footer, which lets you style the gap around a group differently from the lines inside it. Both are rendered inside the item cells, so a section with no items gets no separators. When you pass a component (not an element), it receives `highlighted`, `section`, `leadingItem`, `trailingItem`, `leadingSection` and `trailingSection`, plus anything set through `separators.updateProps`; `separators.highlight()` in `renderItem` toggles `highlighted` on the separators around that row. A section can override `ItemSeparatorComponent` on its own section object. In a music library, thin inset lines between artists and a full-width rule around each letter group is the typical split.
code
tsx · 36 linesimport {SectionList, StyleSheet, Text, View} from 'react-native';
type Artist = {id: string; name: string};
type LetterSection = {key: string; title: string; data: Artist[]};
// Component form: receives highlighted, section, leading/trailing props.
function ArtistLine({highlighted}: {highlighted?: boolean}) {
return <View style={[styles.line, highlighted && styles.hidden]} />;
}
function GroupGap() {
return <View style={styles.gap} />;
}
export function ArtistList({sections}: {sections: LetterSection[]}) {
return (
<SectionList
sections={sections}
keyExtractor={a => a.id}
ItemSeparatorComponent={ArtistLine} // between artists of one letter
SectionSeparatorComponent={GroupGap} // before first and after last artist
renderSectionHeader={({section}) => (
<Text style={styles.header}>{section.title}</Text>
)}
renderItem={({item}) => <Text style={styles.row}>{item.name}</Text>}
/>
);
}
const styles = StyleSheet.create({
line: {height: StyleSheet.hairlineWidth, marginLeft: 12, backgroundColor: '#d4d4d8'},
hidden: {opacity: 0},
gap: {height: 8},
header: {backgroundColor: '#ffffff', paddingHorizontal: 12, fontWeight: '700'},
row: {paddingHorizontal: 12, paddingVertical: 10},
});go deeper
Recall the split: item separators between rows of one section, section separators before the first and after the last row of each section.
Explain the props separators receive, including leading and trailing items and sections, and why only the component form gets them. Know that highlight toggles the separators around a row.
Predict the rendered lines for edge cases: empty sections, the gap before the next header, per-section item separator overrides, and separator height inside measured cells.
Keep grouped-list styling in one shared set of separator components so every grouped screen draws group boundaries the same way.
## Two separators, two jobs A `FlatList` has one separator slot. A `SectionList` has two, because grouped lists usually need two kinds of lines: | Prop | Where it renders | Typical look | |---|---|---| | `ItemSeparatorComponent` | between adjacent items **of the same section** | a thin line, inset from the left | | `SectionSeparatorComponent` | before a section's first item and after its last item | a full-width rule or extra spacing | The docs describe `SectionSeparatorComponent` as "rendered at the top and bottom of each section", adding that this is different from `ItemSeparatorComponent`, "which is only rendered between items". In the implementation: - the first item of each section renders the section separator **before** itself (between the section header and that item); - the last item of each section renders the section separator **after** itself, and no item separator; - every other item renders the item separator after itself. ## Consequences of rendering inside item cells Separators are drawn as part of the item cells, not as cells of their own. That has practical effects: 1. **An empty section has no separators**, because it has no item cells; its header and footer render back to back. 2. **Without a section separator, there is no line between the last item of one section and the next header**, because the item separator is suppressed after a section's last item. 3. Separator height is part of the item cell's measured size, which matters if you compute item layouts yourself. ## The props separators receive When you pass a **component** (for example `SectionSeparatorComponent={LetterRule}`), React Native renders it with: - **`highlighted`** — toggled by `separators.highlight()` and `separators.unhighlight()` from `renderItem`, which update the separators around that row, for example to hide lines while a row is pressed; - **`section`** — the section the separator belongs to; - **`leadingItem`** and **`trailingItem`** — the items above and below it, when there are any; - **`leadingSection`** and **`trailingSection`** — the neighbouring sections; - any props you set with `separators.updateProps('leading' | 'trailing', newProps)`. When you pass an **element** (for example `ItemSeparatorComponent={<View style={styles.line} />}`), the element is rendered as-is, and none of these props reach it. Use the component form whenever a separator must react to highlighting or to its neighbours. ## Per-section overrides A section object may carry its own `ItemSeparatorComponent`, which replaces the list-level one inside that section. A music library could use a thicker line between items in a "Favourites" section and the standard inset line elsewhere. `SectionSeparatorComponent` is list-level only. ## Building the music library look For an A-Z artist list: - `ItemSeparatorComponent`: a hairline inset to line up with the artist name; - `SectionSeparatorComponent`: a small vertical gap, so each letter group reads as a block; - `renderSectionHeader`: the letter, with an opaque background if headers stick. ## Common mistakes - Expecting `ItemSeparatorComponent` to draw a line under the last artist before the next letter. - Passing separators as elements and wondering why `highlighted` never changes. - Leaving empty sections in the data and getting a header with no separators or rows. - Adding borders to every row as well as separators, doubling the lines.
- Why is there no line between the last artist under A and the B header?`ItemSeparatorComponent` is suppressed after the last item of a section; it only draws between items of the same section. The gap after the last item is the job of `SectionSeparatorComponent`, which renders after a section's last item and before its first.
- Why does a separator passed as <View style={styles.line} /> never receive highlighted?When a separator is given as an element, the list renders that element as-is. Only the component form, such as `ItemSeparatorComponent={ArtistLine}`, is rendered with `highlighted`, `section` and the leading and trailing props injected.
saying these in an interview costs you the question
- ItemSeparatorComponent also renders between the last item and the next section header.
- SectionSeparatorComponent renders only once, between two sections.
- Separators passed as elements still receive the highlighted prop.
- An empty section renders its section separators around the header.
- SectionSeparatorComponent can be overridden on each section object.