How it works
A DropProposal is the value a drop delegate returns to tell SwiftUI how it intends to consume an incoming drag — whether it will copy, move, link, or refuse the dragged content. Because a delegate is consulted continuously as the pointer moves over a target, the proposal lets you steer the drag's outcome before the user releases, which in turn drives the cursor badge the system shows. Reach for DropProposal whenever you implement DropDelegate and need finer control over the proposed operation than the default onDrop behavior provides.
Return a proposal from dropUpdated(info:)
The
dropUpdated(info:)method ofDropDelegateis called repeatedly while a drag hovers, and its return type isDropProposal?. Returning a proposal advertises how you'll handle a release at the current location; returningnilfalls back to the system default. HereTextDropreturns a freshDropProposaleach time the pointer updates over the target.Choose the operation in the initializer
DropProposal(operation:)takes aDropOperation—.copy,.move,.link,.forbidden, or.cancel— that names the intended action and determines the badge drawn next to the cursor. The example proposes.copy, signaling that dropping will duplicate the dragged text rather than move it out of its source.Pair the proposal with a performDrop decision
The proposal only states intent;
performDrop(info:)does the work and returns aBoolfor success. Keep the two consistent: becauseTextDropproposes.copyindropUpdated, itsperformDropaccepts the drop and returnstrue, invokingonDropto updatedropped.Attach the delegate with onDrop(of:isTargeted:delegate:)
A
DropProposalreaches the view through the delegate form ofonDrop. TheonDrop(of:isTargeted:delegate:)modifier wiresTextDropto the target and binds$isTargetedso you can react to hovering, while theof:argument (["public.text"]) gates which uniform type identifiers the delegate — and therefore your proposal — even sees.
DropProposal(operation: .copy) to DropProposal(operation: .forbidden) and watch the cursor show a no-drop badge as the proposal refuses the drag.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 DropProposalDemo: View {
@State private var dropped = "Drop text here"
@State private var isTargeted = false
struct TextDrop: DropDelegate {
let onDrop: () -> Void
func dropUpdated(info: DropInfo) -> DropProposal? {
DropProposal(operation: .copy)
}
func performDrop(info: DropInfo) -> Bool {
onDrop()
return true
}
}
var body: some View {
VStack(spacing: 16) {
Text("Drag onto the box")
.font(.headline)
Text(dropped)
.frame(maxWidth: .infinity, minHeight: 80)
.background(isTargeted ? Color.blue.opacity(0.2) : Color.gray.opacity(0.15))
.cornerRadius(12)
.onDrop(of: ["public.text"], isTargeted: $isTargeted, delegate: TextDrop { dropped = "Dropped!" })
}
.padding()
}
}