WWDC23 SALE: Save 50% on all my Swift books and bundles! >>

How to hide the label of a Picker, Stepper, Toggle, and more using labelsHidden()

Paul Hudson    @twostraws   

Updated for Xcode 14.2

SwiftUI requires that we add labels to its controls, and it’s common to want to hide those labels so you can get a more precise UI layout. However, there’s a bad way of hiding labels and a good way, and it’s already common to see folks choosing the bad choice despite it actively hurting users.

First, let’s look at the right way to hide labels. As an example, here’s a Picker that lets users select a number:

struct ContentView: View {
    @State private var selectedNumber = 0

    var body: some View {
        Picker("Select a number", selection: $selectedNumber) {
            ForEach(0..<10) {
                Text("\($0)")
            }
        }
    }
}

Download this as an Xcode project

On some platforms, that will show “Select a number” alongside the picker. This can look poor, because the label is sometimes crammed into a small space – a better idea would be to have a VStack with a custom text label, then hide the label in the Picker.

To hide the label for a Picker – or indeed for a DatePicker, a Stepper, a Toggle, or any other view that requires a label – you should add the labelsHidden() modifier to the view, like this:

struct ContentView: View {
    @State private var selectedNumber = 0

    var body: some View {
        Picker("Select a number", selection: $selectedNumber) {
            ForEach(0..<10) {
                Text("\($0)")
            }
        }
        .labelsHidden()        
    }
}

Download this as an Xcode project

A wheel-style picker offering the numbers 0, 1, 2, etc. 0 is selected.

That still creates the label, but now it doesn’t get shown no matter what platform is used. As a result, you can put the Picker inside a VStack and add a label of your own choosing.

Tip: If you want all your labels hidden you can apply the labelsHidden() modifier to a VStack or whatever you’re using as your outermost container.

In case you were curious, the wrong way to hide labels is using EmptyView, like this:

struct ContentView: View {
    @State private var selectedNumber = 0

    var body: some View {
        Picker(selection: $selectedNumber, label: EmptyView()) {
            ForEach(0..<10) {
                Text("\($0)")
            }
        }
    }
}

Download this as an Xcode project

Yes, the end result might look the same, but there’s an important reason why using labelsHidden() is much better: the hidden label is still accessible by the screen reader, so even though the text isn’t visible it’s still there to help VoiceOver understand how your UI is structured.

Save 50% in my WWDC23 sale.

SAVE 50% To celebrate WWDC23, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.8/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.