Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Best way to render iOS List-style gray separators between items (without being part of the active element) #467

Unanswered
outaTiME asked this question in Q&A
Discussion options

I want to replicate the iOS List-style gray separators that appear permanently between items (not the drag insertion indicator).

ScreenRecording_09-01-2025.17-46-25_1.MP4

Right now, I can approximate the look with a bottom border on each item (except the last one). However, I’d prefer separators that are outside of the active element, so when an item is being dragged it stays visually clean and doesn’t carry its separator with it.

My current approach is to interleave explicit separator-* items in the data and render them as fixed-order handles. It works to some extent, but I’m seeing issues (described below).

const data = React.useMemo(
 () =>
 _.flatMap(rateTypes, (type, index) =>
 index < rateTypes.length - 1
 ? [{ id: type }, { id: `separator-${index}` }]
 : [{ id: type }],
 ),
 [rateTypes],
);
const renderItem = React.useCallback(
 ({ index, item: { id } }) => {
 const isFirst = index === 0;
 const isLast = index === data.length - 1;
 const isSeparator = id.startsWith('separator');
 return (
 <ContentView
 contentContainerStyle={[
 {
 backgroundColor: Settings.getContentColor(theme, false, isModal),
 marginVertical: 0,
 marginHorizontal: Settings.CARD_PADDING * 2,
 },
 isFirst && {
 borderTopLeftRadius: Settings.BORDER_RADIUS,
 borderTopRightRadius: Settings.BORDER_RADIUS,
 },
 isLast && {
 borderBottomLeftRadius: Settings.BORDER_RADIUS,
 borderBottomRightRadius: Settings.BORDER_RADIUS,
 },
 ]}
 >
 {isSeparator ? (
 <Sortable.Handle mode="fixed-order">
 <Separator />
 </Sortable.Handle>
 ) : (
 <CardItemView
 title={Settings.getRateTitle(id)}
 chevron={false}
 >
 <Sortable.Handle>
 <ActionView
 community
 iconName="drag-horizontal-variant"
 />
 </Sortable.Handle>
 </CardItemView>
 )}
 </ContentView>
 );
 },
 [data.length, isModal, theme],
);
<Sortable.Grid
 activeItemScale={1}
 autoScrollSpeed={0.5}
 data={data}
 dragActivationDelay={0}
 overDrag="vertical"
 renderItem={renderItem}
 customHandle
 onOrderChange={() => {
 Settings.HAPTICS_ENABLED && Haptics.selectionAsync();
 }}
 onDragEnd={({ data: newData }) => {
 const customRateTypes = _.filter(
 _.map(newData, 'id'),
 (id) => id && !id.startsWith('separator'),
 );
 // save here
 Settings.HAPTICS_ENABLED && Haptics.selectionAsync();
 }}
 onDragStart={() => {
 Settings.HAPTICS_ENABLED && Haptics.selectionAsync();
 }}
/>

Issues I’m seeing

  • With this approach, elements sometimes get stuck when dragging over separators.
  • On Android, separators are rendered above the active item while it’s being dragged (z-order issue).
  • I’m not sure if using <Sortable.Handle mode="fixed-order"> for separators is the right approach, or if I’m misusing it.

Desired behavior

  • Permanent iOS List-style gray separators between items, without being part of (or visually overlapping) the active element.
  • Ideally, the active item would round its corners when dragged to the first/last position, and remain squared when in the middle (just like iOS Lists).

Questions

  1. What’s the recommended way to implement iOS List-style separators with react-native-sortables?
  2. Should separators be handled differently (instead of being added as fixed-order handles), or rendered outside the item container?
  3. Are the "stuck while dragging over separators" and Android z-order issues expected with this setup, or should they be reported as bugs?

Thanks in advance for any guidance or patterns!

You must be logged in to vote

Replies: 1 comment 1 reply

Comment options

Hey! Thanks for asking about that. Honestly, I didn't think about the separators support before so I can't quickly suggest what's best to do here.

  1. What’s the recommended way to implement iOS List-style separators with react-native-sortables?

Since the iOS list is not sortable (at least I don't know about any sortable list with separators on iOS), we would have to come up with our own solution for that and I don't have any recommended approach.

  1. Should separators be handled differently (instead of being added as fixed-order handles), or rendered outside the item container?

As far as I understand you, these separators are for visual purposes only and should always stay at the same position. How about rendering them in the background then? You can render a Sortable.Grid with a very little rowGap having the same width as the separator and render separators as very narrow lines in equal distances matching the height of the item. It should work much better and you won't experience overlaps or other issues.

  1. Are the "stuck while dragging over separators" and Android z-order issues expected with this setup, or should they be reported as bugs?

Is that Android only issue? In general, there should be any difference between Android and iOS if there is an issue with reordering. Maybe this is caused by the fact that separators are very narrow and reordering is buggy in that case. I didn't test that with that many small elements used as separators so this might be a bug.

You must be logged in to vote
1 reply
Comment options

Thanks a lot for the thoughtful reply — really appreciate the detail!

My main goal with this discussion was to get your view on what you consider the best approach for handling separators. Regarding the rowGap idea: I see the logic, but a thin, constant gap (like StyleSheet.hairlineWidth) feels a bit off, since in the iOS List pattern separators only appear between intermediate items (not above the first or below the last).

To share back with the community, I put together an Expo Snack that simulates the iOS behavior as closely as possible (like in the video I shared). In my approach, the separator is placed at the bottom of each item, hidden while the item is active, shown again on drop (if it’s not the last item), and the corners are rounded when the item is at the top or bottom:

https://snack.expo.dev/@outatime/react-native-sortables

It gets quite close to what I needed. If you have any suggestions or improvements for the code itself, I’d be happy to try them out.

One extra note: I haven’t fully tested on a physical Android device yet. In emulators, very thin separators sometimes seem to disappear. I’m not sure if that’s just an emulator rendering quirk or something related to element size calculation with hairline widths. I’ll re-check on real hardware and update if I can reproduce it.

Thanks again for the guidance and for maintaining this library — it’s been really helpful! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /