TechnologiesSwiftUIDrag and Drop

DragSession struct

iOSmacOStvOSwatchOSvisionOS✓ renders

Describes the ongoing dragging session.

How it works

A DragSession is the value SwiftUI hands you to describe a single drag operation while it is underway — the gesture that begins when a person picks up content and continues until they drop it or cancel. Rather than tracking pointer events yourself, you read a DragSession to learn what is being carried, where the drag currently is, and how its lifecycle is progressing. Reach for it when a plain draggable/dropDestination pair isn't enough and you need to coordinate behavior over the lifetime of the drag, such as customizing the preview, animating the source, or responding as the drag moves across your interface.

  1. Start a drag with draggable(_:)

    A DragSession only exists once a draggable view is lifted, so the session begins at the source. Here .draggable("Apple") marks the Text("🍎 Apple") view as a drag source and supplies the String payload that the session will carry. The transferable payload you provide is exactly what the session vends to any destination during the drag.

  2. Receive the payload at a dropDestination(for:)

    A DragSession is resolved at a drop target, where SwiftUI delivers the items the session was carrying. The .dropDestination(for: String.self) modifier on the Text(dropped) view accepts drags whose payload decodes to String, handing your closure the items array; the example takes items.first and assigns it into the dropped state. The session's matched type (String.self) is what lets the destination opt in to this particular drag.

  3. Read the in-progress state during the drag

    While the gesture is active, a DragSession carries the live state of the operation — the dragged items, the current location, and the phase of the drag. You inspect these members from the API surfaces that vend a session (such as a drop destination's location-aware callbacks) to drive feedback as the user moves over a target like the .blue.opacity(0.15) drop zone, before the payload is committed in the closure that sets dropped.

  4. Drive UI from the session's outcome

    Because the session ends with either a completed drop or a cancellation, you tie your view's reaction to that conclusion. The drop closure returns true to signal a successful drop and mutates @State private var dropped, so SwiftUI re-renders the destination Text with the carried value once the session completes.

Try it — Change .draggable("Apple") to .draggable("Banana") and run the demo — dragging onto the blue zone now sets dropped to "Banana", confirming that the session carries the exact payload you hand the source.

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.

DragSession.swift
struct DragSessionDemo: View {
    @State private var dropped = "Drop here"

    var body: some View {
        VStack(spacing: 20) {
            Text("🍎 Apple")
                .font(.title2)
                .padding()
                .background(.yellow.opacity(0.3), in: RoundedRectangle(cornerRadius: 12))
                .draggable("Apple")

            Text(dropped)
                .font(.headline)
                .frame(maxWidth: .infinity, minHeight: 80)
                .background(.blue.opacity(0.15), in: RoundedRectangle(cornerRadius: 12))
                .dropDestination(for: String.self) { items, _ in
                    dropped = items.first ?? ""
                    return true
                }
        }
        .padding()
    }
}
Live preview
🍎 Apple Drop here
🍎 Apple Drop here
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →