How it works
EditableCollectionContent is the structure SwiftUI wraps around the dynamic content of a collection-presenting container, such as a List, when that content needs to support in-place editing. You rarely name this type directly; instead, you produce it by attaching editing actions to a ForEach and SwiftUI threads the wrapper through the surrounding container so it can offer delete and move affordances. Reach for it conceptually whenever you want rows that the user can remove or reorder, and you want the framework to manage the gestures, animations, and edit mode for you.
Back the content with mutable state
In-place editing means the collection must change a value your view owns, so the data source is a mutable property rather than a constant. Here
@State private var fruitsholds the array that the wrapped content edits, and every delete or move mutatesfruitsdirectly so the view re-renders with the new order.Generate per-element content with ForEach
EditableCollectionContent wraps the dynamic rows produced by a
ForEach, which is what gives each element a stable identity to delete or move. TheForEach(fruits, id: \.self)here enumerates the array and renders aText(fruit)per item, and it is this ForEach that the editing modifiers attach to.Enable deletion with onDelete
Attaching
.onDeleteto the ForEach opts its content into the editable wrapper's removal behavior and surfaces swipe-to-delete and edit-mode delete controls. SwiftUI hands the closure an IndexSet, which the example forwards tofruits.remove(atOffsets: $0)to drop the selected rows from the source array.Enable reordering with onMove
Pairing
.onMovewith the ForEach lets the wrapped content participate in drag-to-reorder, exposing move handles when the list enters edit mode. The closure receives the source offsets and a destination, andfruits.move(fromOffsets: $0, toOffset: $1)applies that reordering to the underlying array.Toggle edit mode with EditButton
The delete and move affordances appear when the surrounding container is in edit mode, so the example places an
EditButton()in the.toolbar. Tapping it flips the environment's edit mode, at which point the editable content reveals its reorder handles and inline delete buttons.
.onMove { fruits.move(fromOffsets: $0, toOffset: $1) } line and tap Edit: the rows still show delete controls but lose their reorder handles, showing how each modifier contributes a distinct editing capability to the wrapped content.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct EditableCollectionContentDemo: View {
@State private var fruits = ["Apple", "Banana", "Cherry", "Date"]
var body: some View {
NavigationStack {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
}
.onDelete { fruits.remove(atOffsets: $0) }
.onMove { fruits.move(fromOffsets: $0, toOffset: $1) }
}
.navigationTitle("Fruits")
.toolbar { EditButton() }
}
.padding()
}
}