Mobile Swipe Actions
This note documents a recurring React Native list issue: a swipe action is visible, but pressing the action does nothing.
Symptom
- The list row can be swiped and the action button is visible.
- Screen-level logs inside
renderLeftActionsorrenderRightActionsappear. - Logs inside the action button
onPressdo not appear. - The issue can look like a permission or business-rule problem, but the press event never reaches the action button.
Root cause
SwipeableFlashList renders action buttons behind the card and moves the card with translateX.
If the translated card content still has a higher touch layer than the action area, the action can be visible while the card layer still receives the tap. In this repo, itemContent already has zIndex: 1, so action layers must be explicitly raised above it.
Fix pattern
In apps/mobile/src/components/SwipeableFlashList/index.tsx:
- set
pointerEvents="box-none"on the action wrapper and inner action-content wrapper - keep the action wrapper at
pointerEvents="none"until the row is actually open; otherwise invisible actions can be pressed before swiping - give both
leftActionsandrightActionsa higherzIndexandelevationthanitemContent - keep the action
Pressableenabled when debug logs are needed, even if no business action should run
Expected action-layer shape:
<Animated.View
pointerEvents={actionsTouchable ? 'box-none' : 'none'}
style={[styles.leftActions, leftActionStyle]}
>
<View pointerEvents="box-none" style={styles.actionContent}>
{leftActions}
</View>
</Animated.View>
Set actionsTouchable to true only when the pan gesture decides to open the row, and set it back to false on close/reset. This prevents invisible action buttons from receiving taps while still allowing visible buttons to be pressed after a swipe.
Expected styles:
leftActions: {
...StyleSheet.absoluteFill,
zIndex: 2,
elevation: 2,
},
rightActions: {
...StyleSheet.absoluteFill,
zIndex: 2,
elevation: 2,
},
itemContent: {
width: '100%',
zIndex: 1,
},
Debug checklist
- Log inside
renderLeftActionsandrenderRightActions. - Log inside the action
PressableonPress. - If render logs appear but press logs do not, inspect the swipe action layer, not the permission logic.
- Confirm swipe direction:
leftActionsopens when the row is dragged to the right.rightActionsopens when the row is dragged to the left.
- If a disabled-looking action still needs debug logging, keep the
Pressableenabled and callconfig.onPress?.()conditionally.
Invoice example
invoiceListScreen uses this pattern to debug cancel actions. The useful logs are:
[InvoiceListScreen] cancel swipe render[InvoiceListScreen] swipe action press[InvoiceListScreen] cancel swipe press
When checking owner permissions, log both:
loginUserCodeinvoiceUserCoderawInvoiceUserCode
Normalize numeric user codes before comparing because API data can omit leading zeroes. For example, 12265 and 012265 must compare as the same user.