TechnologiesSwiftUI

DropDelegate protocol

iOSmacOStvOSwatchOSvisionOS✓ renders

An interface that you implement to interact with a drop operation in a view

How it works

DropDelegate is a protocol you adopt to take fine-grained control of a drag-and-drop interaction landing on a view. Where the closure-based onDrop modifiers handle simple cases, a delegate lets you respond to every phase of a drop — when content enters, moves within, and leaves the drop region, whether the proposed drop is allowed, and how to extract the dropped items. Reach for it when a single drop callback isn't enough and you need to validate, preview, or stage the operation as the user drags.

  1. Conform a type to DropDelegate

    DropDelegate is a protocol, so you declare a value type that adopts it and supply the behavior the view will call into. Here the nested struct ColorDrop: DropDelegate is that conformer, carrying a @Binding var dropped so it can write back into the view's state when a drop succeeds.

  2. Implement performDrop(info:) to consume the items

    The only required member is performDrop(info:), which the system calls when the user releases content over the view. It receives a DropInfo describing the dropped items and returns a Bool to report whether the drop was accepted. In the example it flips dropped = true and returns true to signal success.

  3. Read the drop payload from DropInfo

    Every delegate callback is handed a DropInfo, the gateway to the in-flight drag — its location, the uniform types present, and the item providers you load data from. Optional members like validateDrop(info:), dropEntered(info:), dropUpdated(info:), and dropExited(info:) all receive this same info so you can inspect and react throughout the gesture.

  4. Attach the delegate with onDrop(of:delegate:)

    A DropDelegate only takes effect once a view installs it. The onDrop(of:delegate:) modifier wires the conformer to a target, declaring which uniform types it accepts and which delegate handles them — here .onDrop(of: [.url], delegate: ColorDrop(dropped: $dropped)) makes the rectangle a live drop zone for URLs.

  5. Drive view state from the delegate

    Because the delegate is a plain value, you pass bindings into it so its callbacks can mutate SwiftUI state. The $dropped binding handed to ColorDrop lets performDrop(info:) update @State private var dropped, which in turn re-renders the rectangle's fill and overlay text.

Try it — Add a func dropEntered(info: DropInfo) { dropped = true } to ColorDrop so the zone turns green the moment a drag hovers over it, before the user even releases.

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.

DropDelegate.swift
struct DropDelegateDemo: View {
    @State private var dropped = false

    struct ColorDrop: DropDelegate {
        @Binding var dropped: Bool
        func performDrop(info: DropInfo) -> Bool {
            dropped = true
            return true
        }
    }

    var body: some View {
        VStack(spacing: 16) {
            Text("Drag a URL here")
            RoundedRectangle(cornerRadius: 12)
                .fill(dropped ? Color.green : Color.gray.opacity(0.3))
                .frame(width: 160, height: 100)
                .overlay(Text(dropped ? "Dropped!" : "Drop Zone"))
                .onDrop(of: [.url], delegate: ColorDrop(dropped: $dropped))
        }
        .padding()
    }
}
Live preview
Drag a URL here Drop Zone
Drag a URL here Drop Zone
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →