How to Delete List rows from SwiftUI List

⋅ 4 min read ⋅ SwiftUI List

Table of Contents

SwiftUI List has many built-in features equipped. The way we enable these features is by attach a view modifier in a view hierarchy.

The view modifier that enable the delete function is onDelete(perform:).

How to Delete List rows from SwiftUI List

To enable the delete function in SwiftUI List, you need to do the following steps.

  1. Create a data source
  2. Populate a List view using ForEach.
  3. Apply onDelete(perform:) modifier to the ForEach.
  4. Manually delete items in the onDelete's handler.

Create Data Source

Since you want to delete an item in a List view, your data source must be mutable.

I use a @State variable as a data source in this example.

@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

Create a List view with ForEach

The onDelete modifier only works with ForEach, so we need to populate our List view using ForEach.

struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}
}
}
}

Apply onDelete modifier on ForEach

Apply onDelete modifier on ForEach to enable the delete function.

struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onDelete { indexSet in
// TODO: delete items
}
}
}
}

Delete items from the Data Source

The onDelete modifier doesn't automatically delete an item from your data source. You have to do it yourselves.

The onDelete perform action pass IndexSet as an argument. This is the set of indices of items about to be deleted.

.onDelete { deleteOffsets: IndexSet in

}

We use the passing indices to remove the item from our data source. Swift Array already has a remove(atOffsets:) method that takes an IndexSet as an argument.

struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onDelete { indexSet in
contacts.remove(atOffsets: indexSet)
}
}
}
}

What does onDelete do

Adding an onDelete(perform:) modifier will enable the ability to delete items in that List view.

Users can delete the List item in two ways.

  1. Swipe to delete
  2. Deleting items in EditMode

Swipe to delete

Users can swipe from right to left on any list row to delete that particular row.

Swipe to delete
Swipe to delete

Deleting items in EditMode

Another way to delete the list item is in the edit mode.

There are two options to enter the edit mode.

  1. Using the EditButton
  2. Setting the .editMode environment value

I will use EditButton in this case.

struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

var body: some View {
// 1
NavigationView {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onDelete { indexSet in
contacts.remove(atOffsets: indexSet)
}
}
.toolbar {
// 2
EditButton()
}
}
}
}

I wrap the List view inside NavigationView` 1 and add the Edit button there 2.

Once you enter the Edit mode by tapping the "Edit" button, you will see the delete button in front of each row.

Edit Mode.
Edit Mode.

How to conditionally Disable the Delete ability

If you want to disable the delete ability based on some condition, you can do that by passing nil to the onDelete.

ForEach(contacts, id: \.self) { contact in
Text(contact)
}
.onDelete(perform: nil)

Here is an example where we control reorder ability from the boolean value, enableDelete.

struct DeleteExample: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]

// 1
@State private var enableDelete = true

var body: some View {
NavigationView {
List {
Toggle("Enable Delete", isOn: $enableDelete)
ForEach(contacts, id: \.self) { contact in
Text(contact)
}
// 2
.onDelete(perform: enableDelete ? delete: nil)
}
.toolbar {
EditButton()
}
}

}

// 3
func delete(at offsets: IndexSet) {
contacts.remove(atOffsets: offsets)
}
}

1 A state variable use to control delete ability.
2 We use enableDelete to conditionally enable/disable the delete ability. We disable it by set perform closure as nil.
3 We extract a delete logic out as a separate function to improve readability.

Disable the delete ability by passing nil to the onDelete.
Disable the delete ability by passing nil to the onDelete.

Read more article about SwiftUI, List, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
What is Swift If Case

Learn how to match a single case of an enum with an if-case syntax.

Next
How to change Status Bar text color in SwiftUI

Learn how to change a status bar text color in SwiftUI.

← Home