useSwipeActions
Reveal actions behind a row with a horizontal swipe, with an optional full swipe.
Draft
The API shown here is conceptual and may change.
The hook behind Swipe actions. That page explains the direction lock, the resistance, the release rules, the full swipe and accessibility. This one covers the API.
Installation
npx axiom add use-swipe-actionspnpm dlx axiom add use-swipe-actionsyarn dlx axiom add use-swipe-actionsbun x axiom add use-swipe-actionsInstalls: react-native-reanimated, react-native-gesture-handler.
Usage
SwipeableRow covers most lists. It calls the hook, draws the actions behind its child and adds the accessibilityActions.
import { SwipeableList, SwipeableRow } from "@/components/swipeable-row";
function Inbox() {
return (
<SwipeableList>
<FlatList
data={mails}
renderItem={({ item }) => (
<SwipeableRow
leading={[
{
key: "read",
icon: "mail",
label: "Read",
color: "info",
onPress: () => toggleRead(item),
},
]}
trailing={[
{
key: "flag",
icon: "flag",
label: "Flag",
color: "warning",
onPress: () => flag(item),
},
{
key: "delete",
icon: "trash",
label: "Delete",
color: "error",
fullSwipe: true,
onPress: () => remove(item),
},
]}
>
<Item onPress={() => open(item)}>…</Item>
</SwipeableRow>
)}
/>
</SwipeableList>
);
}SwipeableList holds the id of the open row, so opening one closes the other. It doesn’t render anything.
Custom actions
Call the hook yourself to draw the actions differently, for example icons that grow with the swipe.
function Row({ mail }: { mail: Mail }) {
const swipe = useSwipeActions({
leadingWidth: 80,
trailingWidth: 160,
fullSwipe: "trailing",
});
const content = useAnimatedStyle(() => ({
transform: [{ translateX: swipe.translateX.value }],
}));
const icon = useAnimatedStyle(() => ({
transform: [{ scale: 0.8 + swipe.progress.value * 0.4 }],
}));
return (
<View>
<TrailingActions
style={icon}
armed={swipe.armed}
onPress={swipe.close}
/>
<GestureDetector gesture={swipe.gesture}>
<Animated.View style={content}>…</Animated.View>
</GestureDetector>
</View>
);
}Closing from code
close() animates the row back. Call it after an action that keeps the row, or when the list starts scrolling:
<FlatList onScrollBeginDrag={swipeableList.closeAll} … />Options
| Option | Type | Default | Description |
|---|---|---|---|
leadingWidth | number | 0 | Width in pt of the leading actions. 0 turns the right swipe off. |
trailingWidth | number | 0 | Width in pt of the trailing actions. 0 turns the left swipe off. |
resistance | number | 60 | Maximum extra distance past the actions’ width. Ignored on a side with fullSwipe. |
velocityThreshold | number | 500 | Release speed in pt/s that opens or closes whatever the position. |
fullSwipe | 'leading' | 'trailing' | false | false | Side where a long swipe triggers the outermost action. |
fullSwipeThreshold | number | 0.55 | Fraction of the row width that arms the full swipe. |
onFullSwipe | (side: 'leading' | 'trailing') => void | — | Called on release while armed, after the row has left the screen. |
onArmedChange | (armed: boolean) => void | — | Called when the full swipe arms or disarms. Default: a light haptic. |
enabled | boolean | true | Turns the swipe off, for example in selection mode. |
Return value
| Key | Type | Description |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------- | ---------- | --------------------------- |
| translateX | SharedValue<number> | Row offset in pt. Negative reveals the trailing actions. |
| progress | SharedValue<number> | | translateX | / rowWidth, from 0to1. |
| open | 'leading' \| 'trailing' \| null | Open side. React state. |
| armed | boolean | true while a full swipe would trigger on release. React state. |
| close | () => void | Animates the row closed. |
| openSide | (side: 'leading' \| 'trailing') => void | Opens a side from code, for a first-use hint. |
| gesture | PanGesture | For a GestureDetector around the row content. |