`onTapGesture` not triggered on `Map` views

When building with iOS 26 SDK beta 5 (23A5308f), onTapGesture is no longer being triggered on Map views. This appears to be a regression in beta 5 specifically, as this issue was not present in beta 4.

How to reproduce

Code

The following code demonstrates the issue, as seen in the videos below.

import MapKit
import SwiftUI

struct ContentView: View {
  @State private var location = CGPoint.zero

  var body: some View {
    Map()
      .onTapGesture { location in
        self.location = location
      }
      .safeAreaInset(edge: .bottom) {
        VStack(alignment: .center) {
          Text("iOS \(UIDevice.current.systemVersion)")
            .font(.largeTitle)

          Text("Tapped Location")
          Text("\(location.x), \(location.y)")
        }
        .frame(maxWidth: .infinity, alignment: .center)
        .background(.background)
      }
  }
}

Demo

The gifs below show the behavior in iOS 18.5 (in which the tap gestures are recognized and tapped coordinate is displayed in the safe area inset) and iOS 26 beta 5 (in which the tap gestures have no effect):

iOS 18iOS 26

Next steps?

Is there a recommended workaround for this issue?

I've filed FB19405284 describing this bug.

Thank you for filing FB19405284 so we can take a look.

— Ed Ford,  DTS Engineer

Hello, I had the same issue with onTapGesture not being triggered when applied on a struct conforming to UIViewControllerRepresentable. That happens only on iOS 26 Developer Beta 5, not on beta 4.

I can confirm that I'm also experiencing that same issue. I'm happy to provide whatever data I can to debug the issue.

I've also filed FB19394663 which demonstrates the same issue but when Map is wrapped in a MapReader.

I should add that in beta 4 I saw an issue where if I clicked really fast on the map with an onTapGesture interaction modes set to .pan, .zoom, the map eventually stopped responding to everything. With just .pan, it worked just fine, though.

I can also confirm that I am seeing this issue as well when Map view is wrapped in MapReader for iOS 26 (23A5308f))

FYI: I tested this using the new releases published today, and this issue still exists.

Specifically, I observed the issue when:

  • Developing in Xcode beta 6 (17A5305f) running iOS 26 SDK beta 6 (23A5324a) in the simulator
  • Running the sample app on a physical iPhone running iOS 26 beta 7 (23A5326a)

Yes, I can confirm that the issue still exists in Version 26.0 beta 6 (17A5305f) and the iOS 26 SDK beta 6 (23A5324a) in the simulator. Can't understand why it's not fixed :-( Filed a bug (FB19756493)

I can confirm the same in iOS 26 SDK beta 7 when installed on a test device. Deeply frustrating as this has no workaround and is core functionality within our app.

We're still investigating this, but here's something you can try as a workaround: .simultaneousGesture(TapGesture().onEnded {}) to register the callback.

Please let me know how that goes.

— Ed Ford,  DTS Engineer

Accepted Answer

Thanks so much for that suggestion, @DTS Engineer!

That approach does indeed fire the callback for a tap. But in my particular case, I need the screen coordinate of the tap, and I don't see a way to get that using TapGesture().onEnded {}.

However, I found that SpatialTapGesture does provide the screen coordinate of the tap.

Here's what this workaround looks like applied to the code sample from the OP:

import MapKit
import SwiftUI

struct ContentView: View {
  @State private var location = CGPoint.zero

  var body: some View {
    Map()
      .simultaneousGesture(SpatialTapGesture()
        .onEnded { event in
          self.location = event.location
        }
      ).safeAreaInset(edge: .bottom) {
        VStack(alignment: .center) {
          Text("iOS \(UIDevice.current.systemVersion)")
            .font(.largeTitle)

          Text("Tapped Location")
          Text("\(location.x), \(location.y)")
        }
        .frame(maxWidth: .infinity, alignment: .center)
        .background(.background)
      }
  }
}

That seems to work well in my testing!

I'll adopt this workaround for now. Thanks for your help!


Docs:

Thank you to all above for their help with this. I have managed to get the original single tap and longPressGesture working in my app using the following code.

That said, I trust Apple engineers will still resolve the fundamental issue of .onTapGesture not recording a callback. Whilst I am not so concerned about the LongPressGesture, using either spatial or drag inside a simultaneousGesture for what is a single tap feels uncomfortable and a possible future vulnerability...

                    .simultaneousGesture(
                        DragGesture(minimumDistance: 0).onEnded({ value in
                            print("Map tapped")
                            if let coordinate = mapProxy.convert(value.location, from: .local) {
                                self.model.selectedMapLocation = coordinate
                            }
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                                if self.model.isShowingMickDescription != true && self.model.isShowingBeaconDescription != true {
                                    self.isShowingCreatePinFromMap = true
                                }
                            }
                        })
                    )
                    .simultaneousGesture(
                        LongPressGesture().onEnded({ value in
                            print("Long tap gesture")
                            if self.model.nearestPin != nil && self.model.subscribed {
                                self.selectedResult = self.model.nearestPin
                                withAnimation {
                                    visibleRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: self.selectedResult!.dispLat, longitude: self.selectedResult!.dispLon), span: .nearestPinSpan)
                                    cameraPosition = .region(visibleRegion!)
                                }
                                self.model.cameraPosition = self.cameraPosition // Used in Model to save camera position
                                self.model.isShowingMickDescription = true
                            }
                        })
                    )

Just to add to my post above. I have changed from using DragGesture to SpatialGesture as a map drag acts as a tap when using this method (if user pans map with single finger).

I'm also seeing this problem with Swift Charts. This is with the latest Xcode 26 Beta 6 and iOS 26 Beta 8. This issue doesn't affect devices running iOS 18 and 17 from my testing. As such I've made this modifier which may help someone, hopefully I can remove it in the release seed but who knows!

extension View {
    func CustomTapGesture(tapCount:Int = 1, perform action: @escaping () -> Void ) -> some View {
        modifier(TapGestureModifier(tapCount: tapCount, action: action))
    }
}

struct TapGestureModifier: ViewModifier {
    var tapCount:Int = 1
    var action: (() -> Void)
    func body(content: Content) -> some View {
        if #available(iOS 26.0, *) {
            content.simultaneousGesture(TapGesture(count: tapCount).onEnded {
                action()
            })
        }
        else {
            content.onTapGesture(count: tapCount) {
                action()
            }
        }
    }
}

Which can be used like this:

Text("Hello World")
.CustomTapGesture(tapCount:2) {
UIImpactFeedbackGenerator().impactOccurred()
  }

To be clear, this doesn't work as well for iOS 26 users as the standard .onTapGesture but it is a workaround.

Still not fixed in RC, will proceed with the workaround for initial iOS 26 support release.

This issue is noted in the iOS 26 Release Notes (search for FB19394663), so yes, you'll need to keep using the workarounds in this thread for now.

— Ed Ford,  DTS Engineer

For those having to deal with that bug and in need to get location for the tap, I've used the answer here https://stackoverflow.com/questions/56513942/how-to-detect-a-tap-gesture-location-in-swiftui with a slight modification :

import SwiftUI

struct ClickGesture: Gesture {
    let count: Int
    let coordinateSpace: CoordinateSpace
    
    typealias Value = SimultaneousGesture<TapGesture, DragGesture>.Value
    
    init(count: Int = 1, coordinateSpace: CoordinateSpace = .local) {
        precondition(count > 0, "Count must be greater than or equal to 1.")
        self.count = count
        self.coordinateSpace = coordinateSpace
    }
    
    var body: SimultaneousGesture<TapGesture, DragGesture> {
        SimultaneousGesture(
            TapGesture(count: count),
            DragGesture(minimumDistance: 0, coordinateSpace: coordinateSpace)
        )
    }
    
    func onEnded(perform action: @escaping (CGPoint) -> Void) -> _EndedGesture<ClickGesture> {
        self.onEnded { (value: Value) -> Void in
            guard value.first != nil else { return }
            guard let location = value.second?.startLocation else { return }
            guard let endLocation = value.second?.location else { return }
            guard ((location.x-1)...(location.x+1)).contains(endLocation.x),
                  ((location.y-1)...(location.y+1)).contains(endLocation.y) else {
                return
            }
            action(location)
        }
    }
}

extension View {
    func onClickGesture(
        count: Int,
        coordinateSpace: CoordinateSpace = .local,
        perform action: @escaping (CGPoint) -> Void
    ) -> some View {
        simultaneousGesture(ClickGesture(count: count, coordinateSpace: coordinateSpace)
            .onEnded(perform: action)
        )
    }
    
    func onClickGesture(
        count: Int,
        perform action: @escaping (CGPoint) -> Void
    ) -> some View {
        onClickGesture(count: count, coordinateSpace: .local, perform: action)
    }
    
    func onClickGesture(
        perform action: @escaping (CGPoint) -> Void
    ) -> some View {
        onClickGesture(count: 1, coordinateSpace: .local, perform: action)
    }
}

An update regarding the state of this issue as of iOS 26.1 beta 1

Using 26.1 beta 1 (23B5044k), I tested this issue using the sample code provided with the original post, and there's a partial fix in this build of iOS 26.1, but there's a noticeable performance issue that folks will likely want to keep in mind.

There's a significant regression between the responsive UI experience that was present in iOS 18.6 and the high-latency UI experience now present in iOS 26.1. I'll try to summarize how the behavior varies across OS versions:

  • iOS 18.6: onTapGesture triggers callback nearly instantly
  • iOS 26.0: onTapGesture fails to trigger callback at all
  • iOS 26.1: onTapGesture eventually triggers callback, but there's a significant delay that causes the app to feel unresponsive

Demo

The attached gif attempts to show the delay, but it feels much more apparent when you're using an app yourself and you sense the delay between when you personally tap on the screen and when the screen updates. The gif shows the follow:

  1. Using onTapGesture in iOS 18.6: ~100ms between when the user taps and when the view updates to show the GPS coordinates of the tapped location

  2. Using simultaneousGesture in iOS 26.1: ~100ms between when the user taps and when the view updates to show the GPS coordinates of the tapped location. (simultaneousGesture is the workaround demonstrated in https://developer.apple.com/forums/thread/795909?answerId=855111022#855111022.)

  3. Using onTapGesture in iOS 26.1: ~400ms between when the user taps and when the view updates to show the GPS coordinates of the tapped location

Unresponsive UI

To me, the latency of using onTapGesture in iOS 26.1 beta 1 (simulator version 23B5044k) is too severe.

Knowing that Apple cares about apps feeling responsive to touch, I don't think that Apple would accept this latency in Apple's first-party apps.

Along those same lines, I plan to stick with the simultaneousGesture workaround until onTapGesture is as responsive in iOS 26.x as it was in iOS 18.6.

I hope this perspective is helpful.

&#96;onTapGesture&#96; not triggered on &#96;Map&#96; views
 
 
Q