TechnologiesSwiftUIDrag and Drop

DropSession struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A structure that represents an in-progress drop session.

How it works

DropSession represents a single in-progress drop as the user drags content over one of your views. SwiftUI hands you a session so you can inspect what's being carried, decide whether the current view can accept it, and coordinate the visual response before the drop completes. Reach for it whenever a view needs to react to a drag while it's still hovering — not just when the items finally land — so you can validate types, highlight a target, or refuse content that doesn't fit.

  1. Declare a drop target with onDrop(of:isTargeted:)

    A view becomes a drop destination when you attach a drop modifier; the session exists only within the lifetime of that target. Here the RoundedRectangle is made droppable by onDrop(of: [.text], isTargeted: nil), which is the entry point that gives a DropSession something to land on.

  2. Constrain the session by accepted content types

    The of: parameter lists the uniform type identifiers the session is allowed to carry, so SwiftUI can vet a drag before it ever reaches your code. Passing [.text] means this DropSession only proceeds for plain-text payloads, and other content is rejected automatically.

  3. Track hover state with isTargeted

    The isTargeted: binding reflects, in real time, whether the active session is currently over this view — the moment-to-moment signal a DropSession provides. Passing nil opts out of that feedback here, but binding it to state is how you'd drive a highlight while the drag hovers.

  4. Receive the payload and complete the session

    When the user releases, the closure runs with the session's item providers so you can pull out the dropped values. The providers in closure flips dropped = true to record the result, and its return true tells the DropSession the drop was accepted rather than refused.

Try it — Change return true to return false and the DropSession will report the drop as rejected, so the closure's side effects stay but the system treats the content as not accepted.

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.

DropSession.swift
struct DropSessionDemo: View {
    @State private var dropped = false

    var body: some View {
        VStack(spacing: 16) {
            Text("Drag a string here")
                .font(.headline)
            RoundedRectangle(cornerRadius: 12)
                .fill(dropped ? Color.green.opacity(0.3) : Color.gray.opacity(0.2))
                .frame(height: 120)
                .overlay(Text(dropped ? "Dropped!" : "Drop zone"))
                .onDrop(of: [.text], isTargeted: nil) { providers in
                    dropped = true
                    return true
                }
        }
        .padding()
    }
}
Live preview
Drag a string here Drop zone
Drag a string here Drop zone
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →