Articles · How-To GuidesUpdated October 2026

A swipeable row is not in React Native, and the ready made one is iOS only.

There are two routes and you have to pick one before you write anything. Expo documents a SwipeActions component in its @expo/ui package that wraps the native SwiftUI swipe, and its platform badge says iOS and Expo Go, with no Android. For a row that swipes on both platforms the Expo documentation sends you to react-native-gesture-handler, which draws nothing for you and leaves the whole interaction to you. Neither one ships with React Native, so there is an install either way. Every version, prop name and platform badge below comes from the Expo and React Native documentation, read on 23 October 2026 against Expo SDK 58 and React Native 0.87. If you have not got as far as a list on a screen yet, start with make an app.

Then the part that surprises people. Apple's design guidance has no page about swipe actions, and nothing in it tells you how to handle a destructive one. The rules you want are real, and they are filed somewhere else entirely.

Start here

The short version

Pick the platform first, then the library follows.

If the app is iOS and you want the swipe to feel like Mail, Expo's SwipeActions is the shortest path and it costs one install. If the app ships on Android or on web as well, that component has no target there and you build the row yourself on top of react-native-gesture-handler. There is no third option inside React Native itself, because React Native does not ship a swipeable row.

The design half is simpler than the search results suggest. Apple wants swipe actions on list rows, says so once, and leaves the behaviour to you. The only rule that changes what you build is on the Alerts page, and it is about whether the thing behind the swipe can be undone. A reversible delete gets an undo. A permanent one gets a confirmation. That single question decides the design.

Which library do the docs point at for a swipeable row?

Expo documents a component called SwipeActions, in the @expo/ui package, under the SwiftUI half of that package. Its own description is that it matches the official SwiftUI swipeActions modifier and lets you attach leading or trailing actions to row content. The platform badges on the page read iOS and Included in Expo Go. There is no Android badge and no web badge. The recommended version printed on the page was 58.0.22 on 23 October 2026.

The install is one line, npx expo install @expo/ui, and the component is not a drop in replacement for a FlatList row. Expo's own example nests it inside a Host, then a List, then a Section, which are the SwiftUI containers from the same package. Inside the SwipeActions element you put the row content, then one or two SwipeActions.Actions groups. Each group takes an edge, either leading or trailing, and an allowsFullSwipe prop. The buttons inside take a label, a systemImage and a role, and in Expo's example the Delete button on the trailing edge is given the destructive role while the leading group holding a Pin button sets allowsFullSwipe to false.

That whole shape is worth reading closely, because it is Apple's API with React names. The edge decides which side the actions sit on. The full swipe is the long drag that fires the first action without lifting your finger, and turning it off is a single prop rather than a gesture threshold you tune. If you have only ever built this by hand, that prop is the one you did not know you wanted.

For everything cross platform, Expo lists react-native-gesture-handler among its third party libraries, with badges for Android, iOS, Web and Expo Go. Expo quotes the library's own description, that it exposes native touch and gesture handling and runs entirely on the native thread, and then sends you to the library's documentation for the API. Expo's Add gestures tutorial, last modified 22 October 2026, is the closest thing to a worked example in Expo's own words. It wraps the app in a GestureHandlerRootView, noting that gestures are recognised only inside that view, then builds a pan and a tap with GestureDetector and the usePanGesture and useTapGesture hooks. Neither Expo's page for the library nor that tutorial names a prebuilt swipeable row component inside it, so take the component name from the library's own documentation rather than from a page that does not mention it.

Expo, SwipeActions reference for SDK 58, read 23 October 2026

Is any of this part of React Native itself?

No, and the fastest way to be sure is the Core Components and APIs page, which lists every component React Native ships. On version 0.87, last updated 10 September 2026, the list runs from ActivityIndicator to VirtualizedList, with a two item Android group and a two item iOS group after it. There is nothing for a swipeable row. The scrolling components are ScrollView, FlatList, SectionList and VirtualizedList. The touch components are Pressable, the three Touchable variants and TouchableNativeFeedback on Android.

The Handling Touches guide, last updated 14 October 2026, is where people expect to find the answer and it says something narrower than they hope. It covers swipes in one section, called Scrolling and swiping, where swipes and pans are described as the way people scroll a list or move through pages of content, and the component it points at is ScrollView. For anything lower level there is the Gesture Responder System page and PanResponder, which is the hand rolled route and the reason gesture handler exists.

One habit saves time here. Trust the component list, not the prose on a reference page. The RefreshControl page, last updated 12 August 2026, still tells you to use the component inside a ScrollView or a ListView, and ListView is not on the component list at all. A reference page can carry a correct prop table and a stale sentence above it, so check names against the list before you go looking for something that no longer exists.

Android has the piece natively. SwipeToDismissBox and SwipeToDismissBoxState are both in the androidx.compose.material3 API reference. Expo UI does not wrap it. On the Expo UI overview page for SDK 58, read 23 October 2026, the Jetpack Compose component table lists HorizontalPager, LazyColumn, ListItem and PullToRefreshBox, and nothing that puts buttons behind a row. So the asymmetry is about what has been wrapped so far, not about what the platforms can do. The same split shows up with other native surfaces, which is why a sheet you reach for from a row is its own job and not a prop on the swipe. If that is where you are heading, read add bottom sheet next.

What does Apple say about destructive swipe actions?

Nothing, and that is the finding rather than a dodge. The Human Interface Guidelines have no swipe actions page. Searched across the whole of the guidelines on 23 October 2026, a swipe action on a list row comes up in two sentences. The first is on Designing for iOS, where Apple says that because a control in the middle or bottom area of the display is easier to reach, it is especially important to let people swipe to navigate back or initiate actions in a list row. That is Apple telling you to add the feature. The second is on SF Symbols, where the fill variant of a symbol is recommended for iOS tab bars and swipe actions, because its solid areas carry more visual emphasis. That is the whole of it.

The guidance on destructive actions does exist, and it is good. It is just written about buttons. The Buttons page gives a system button four roles, Normal, Primary, Cancel and Destructive, and defines Destructive as a button that performs an action that can result in data destruction. It then says a role can change appearance, and that a destructive button uses the system red colour. So you do not choose a colour for your delete, you choose a role. The same page tells you not to give the primary role to a destructive button even when it is the likeliest choice, because people sometimes pick a prominent button without reading it.

The Alerts page holds the rule that actually changes what you build, and it points the opposite way to most people's instinct. It says to avoid displaying alerts for common, undoable actions, even when they are destructive, and it uses deleting an email or a file as the example: people do it intending to discard the data, and they can undo it. Then it says that when people take an uncommon destructive action they cannot undo, it is important to display an alert in case they started it by accident. A confirmation on every swipe to delete is the thing Apple is arguing against. An undo is the thing it assumes you have.

Two more pages are worth the five minutes. Action sheets says to make destructive choices visually prominent and to put them at the top, which is where a confirmation goes if you need one. Accessibility says to make core functionality reachable through more than one kind of physical interaction, notes that gestures are less comfortable for people with limited dexterity, and uses a swipe to dismiss as its example of a gesture that also needs a button. The Gestures page adds the matching warning for custom work, that a familiar gesture should not do something unique to your app. Taken together they say the swipe is an accelerator and never the only way in.

Apple, Human Interface Guidelines, Designing for iOS, read 23 October 2026

Plan yours

What should the swipe actually do

Tick what you want behind the row. Each one gets the relevant rule from Apple's own design pages, and the thing to build.

Nothing ticked. A list with no swipe is a perfectly good list, and it is what every one of these rows starts as.

What breaks once the delete is behind a swipe?

The first thing is discoverability, and it is not a design opinion. Nothing on the row says a swipe exists. People who have used Mail will try it, and people who have not will never find the action, which is the practical reading of Apple's instruction to offer onscreen ways to achieve the same outcome. Put the same action in a long press menu or on the row's detail screen and the swipe becomes the shortcut it was meant to be.

The second is the full swipe. A long drag that fires the first action is fast, and it is also how a row gets deleted while someone is scrolling with their thumb. On Expo's SwipeActions that is allowsFullSwipe, and Expo's own example sets it to false on the leading group. Turn it off for anything you cannot undo, and leave it on for a toggle, where the worst case is swiping twice.

The third is the list underneath. Removing a row means changing the data behind the list, and FlatList redraws from that data. Delete optimistically and the row leaves immediately, which feels right until the request fails and you have to put it back where it was. Wait for the server and the row sits there with a spinner on it. Neither is wrong. Pick one deliberately, because the choice shows up as an undo button in one case and as a stuck row in the other.

The fourth only appears on the second platform. If you built with Expo's SwipeActions, the Android build has no swipe at all and the list quietly loses the feature. If you built with gesture handler, both platforms work and both look like your design rather than the system's. There is no route that gives you the native swipe on both. Any row that opens a camera or a scanner has the same shape of problem, where one platform does the work for you and the other does not, which is the subject of add document scanner.

The three routes, and what each one costs you

The questionExpo UI SwipeActionsGesture handlerA button in the row
Ships with React NativeNoNoYes
Runs on iOSYesYesYes
Runs on AndroidNoYesYes
Runs on webNoYesYes
Runs in Expo GoYesYesYes
Who draws the swipeSwiftUI does, nativelyYou doThere is no swipe
Turning the full swipe offallowsFullSwipe propYour own thresholdNothing to turn off
What you install@expo/uireact-native-gesture-handlerNothing

Platform badges and install commands from Expo's own reference pages for SDK 58, read 23 October 2026. The third column is there because it is often the right answer for a list that forty people use twice a week.

Where this lands if a builder generated your app

The choice does not go away because an agent wrote the code. Somebody still decides whether the app gets the native iOS swipe or a cross-platform one, and that decision has to be made before the list screen exists, because it changes which containers the rows live inside. Ask for a swipe to delete without saying which platforms matter and you get one of the two, picked for you.

Newly is an AI app builder. You describe an app in plain English and it writes a real React Native and Expo project you own, which means both routes on this page are available to it and the dependency ends up in your package.json either way. It runs the app on cloud iOS and Android simulators while it builds, then ships it to TestFlight and to Google Play internal testing, with a standalone Android APK if you want one. It is $25 a month, with no free plan. Because the project is yours, swapping the route later is a code change in your own repository rather than a support ticket.

The honest limit is the same one Apple sets everywhere. Newly uploads the build and does not press submit for you, because App Store Review Guideline 4.2.6 rejects apps created from an app generation service unless they are submitted directly by the provider of the app's content. The swipe is a two hour job and the submission is a separate afternoon, so read publish to app store before you need it rather than on the day.

Questions people ask about swipe actions in a list

Two, and which one depends on the platforms you need. Expo's reference for SDK 58 documents a SwipeActions component in @expo/ui, which it describes as matching the official SwiftUI swipeActions modifier and letting you attach leading or trailing actions to row content. Its platform badge reads iOS and Included in Expo Go, so there is no Android build of it. For a swipeable row that works on both platforms, the Expo documentation points at react-native-gesture-handler, which it also marks as included in Expo Go and documents for Android, iOS and web. Neither one ships with React Native. Checked on 23 October 2026 against Expo SDK 58.

One install, one edge, and a decision about undo

Name the platforms, pick the route, and settle whether the action behind the swipe can be taken back. Everything else on this page is prop names.

Start building