SwiftUI.cc
Snippets
GesturesGesturesIntermediate

SwiftUI Tap, Long Press, and Drag Gestures

Pick the simplest gesture that matches the user's intent, then promote to explicit Gesture values only when you need state or composition.

5 min readUpdated 2026-06
Draggable card offset
import SwiftUI

struct DraggableCard: View {
    @State private var offset: CGSize = .zero

    var body: some View {
        RoundedRectangle(cornerRadius: 20)
            .fill(.teal.gradient)
            .frame(height: 180)
            .offset(offset)
            .gesture(
                DragGesture()
                    .onChanged { offset = $0.translation }
                    .onEnded { _ in
                        withAnimation(.spring()) { offset = .zero }
                    }
            )
    }
}
Use this when

A view should react to a tap, hold, drag, or swipe without becoming a full custom control.

A drag needs live translation for a card, slider, or reorder preview.

A long press should reveal a secondary action.

Avoid this when

A Button, Toggle, Slider, or ScrollView already provides the expected behavior.

The gesture conflicts with platform navigation gestures.

The interaction cannot be discovered or used with accessibility tools.

Implementation notes

onTapGesture is convenient, but Button remains better for command actions because it carries platform semantics.
DragGesture values include translation and locations, which usually avoids manual coordinate math.
Long-press interactions should have a visible alternative for discoverability.

Checklist

Test inside ScrollView and List because gesture competition changes behavior.

Keep animation reset behavior predictable.

Add accessibility actions for gesture-only features.

Related reference