How to make Empty Space Tappable in SwiftUI

⋅ 2 min read ⋅ SwiftUI

Table of Contents

If you have ever added a tap gesture to a VStack or HStack, you might notice that space between content in a stack isn't tappable.

Tap action only recognizes when you tap on content, e.g., text or an image.

In this example, "onTapGesture" only prints when we tap on the image and text inside an HStack.

struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "swift")
Spacer()
Text("Hello, SwiftUI!")
}
.onTapGesture {
print("onTapGesture")
}
.padding()
}
}
onTapGesture only recognizes when tapping on content, not space.
onTapGesture only recognizes when tapping on content, not space.

How to make Empty Space Tappable in SwiftUI

SwiftUI can't possibly know whether you want the empty space to be tappable or not.

By default, tap gesture only active when user tap on the view content, but not an empty space.

You have to explicitly define the hitting area if the default behavior isn't what you need.

You can define the hitting area using contentShape() modifier.

To make the whole HStack tappable, we define a new hitting area using a rectangle shape, Rectangle().

struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "swift")
Spacer()
Text("Hello, SwiftUI!")
}
.contentShape(Rectangle())
.onTapGesture {
print("onTapGesture")
}
.padding()
}
}

With this simple change, the whole HStack is tappable.

Define a hitting area as a rectangle shape.
Define a hitting area as a rectangle shape.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Use Button or List instead of onTapGesture

Another way to make an empty space in HStack or VStack tappable is by wrapping it inside something that SwiftUI can assume a tappable area, e.g., a button or navigation link.

Users expected the whole area of a button to be tappable, so if you use HStack or VStack as button content, SwiftUI provides the most likely behavior we want. That is, the whole area of that stack view will be tappable.

The same principle applies to a navigation link. Users expected the whole area of a list row to be tappable.

In the following example, the tap action will be active even when tapping a space between the content.

struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink {
Text("Detail")
} label: {
HStack {
Image(systemName: "swift")
Spacer()
Text("Hello, SwiftUI!")
}
}
}
.safeAreaInset(edge: .top) {
Button {
print("Button")
} label: {
HStack {
Image(systemName: "swift")
Spacer()
Text("Hello, SwiftUI!")
}
}
.padding()
}
}
}
}

Using HStack as content for a button and a navigation link.

SwiftUI provides a tappable area that makes sense to that particular UI.
SwiftUI provides a tappable area that makes sense to that particular UI.

Read more article about SwiftUI or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
How to use AttributedString in UIKit

Learn how to use the new AttributedString inside UIKit components.

Next
#file behavior change in Swift 5.8

In Swift 6.0, the behavior of the #file will change. Prepare yourself for the change.

← Home