TechnologiesSwiftUILists and Collections

EditableCollectionContent struct

iOSmacOStvOSwatchOSvisionOSiOS 16.0+✓ renders

An opaque wrapper view that adds editing capabilities to a row in a list.

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.

  1. 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 fruits holds the array that the wrapped content edits, and every delete or move mutates fruits directly so the view re-renders with the new order.

  2. 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. The ForEach(fruits, id: \.self) here enumerates the array and renders a Text(fruit) per item, and it is this ForEach that the editing modifiers attach to.

  3. Enable deletion with onDelete

    Attaching .onDelete to 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 to fruits.remove(atOffsets: $0) to drop the selected rows from the source array.

  4. Enable reordering with onMove

    Pairing .onMove with 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, and fruits.move(fromOffsets: $0, toOffset: $1) applies that reordering to the underlying array.

  5. 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.

Try it — Remove the .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.

EditableCollectionContent.swift
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()
    }
}
Live preview
fruit fruit fruit fruit 9:41 Fruits
fruit fruit fruit fruit 9:41 Fruits
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →