How to Dismiss the Keyboard in SwiftUI: Two Simple Approaches

⌨️ As iOS developers, we often face the challenge of managing keyboard interactions in our apps. One common task is dismissing the keyboard when users are done with text input. In this article, I'll share two simple but effective approaches to keyboard dismissal in SwiftUI (without using UIKit at all :) that I've implemented in my recent project PillsMemo. Method 1: Adding a Toolbar with a Done Button The first approach is straightforward: add a toolbar with a "Done" button that appears above the keyboard. This is particularly useful for keyboard types that don't include a return key, such as the numeric keypad. struct DrugEditorView: View { enum Field: Hashable { case title case quantity case notes } @Bindable var drug: Drug @FocusState private var fieldIsFocused: Field? var body: some View { Form { Section(header: Text("Notes")) { TextEditor(text: $drug.notes) .focused($fieldIsFocused, equals: .notes) .frame(minHeight: 70) } } .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { fieldIsFocused = nil } } } } } This code adds a toolbar above the keyboard with a "Done" button aligned to the right. When tapped, it sets fieldIsFocused to nil, which dismisses the keyboard. Key Points About This Method: The .keyboard placement ensures the toolbar appears directly above the keyboard The Spacer() pushes the "Done" button to the right side Using a @FocusState property with an enum allows precise control over which field has focus (only available in iOS 15 and above) Setting the focus state to nil dismisses the keyboard Method 2: Dismissing When Tapping Outside The second approach creates an invisible, tappable layer that dismisses the keyboard when users tap outside input fields. This solution uses a ZStack with Color.clear and contentShape: @FocusState private var fieldIsFocused: Field? var body: some View { ZStack { Form { Section(header: Text("Notes")) { TextEditor(text: $drug.notes) .focused($fieldIsFocused, equals: .notes) } // ... other form elements } if fieldIsFocused != nil { Color.clear .contentShape(Rectangle()) .onTapGesture { fieldIsFocused = nil } } } } How This Works: We wrap our form in a ZStack to create layering We conditionally add an invisible layer (Color.clear) only when the keyboard is active The contentShape(Rectangle()) ensures the invisible layer captures tap gestures When tapped, it sets fieldIsFocused to nil, dismissing the keyboard

Apr 1, 2025 - 16:43
 0
How to Dismiss the Keyboard in SwiftUI: Two Simple Approaches

⌨️ As iOS developers, we often face the challenge of managing keyboard interactions in our apps. One common task is dismissing the keyboard when users are done with text input.
In this article, I'll share two simple but effective approaches to keyboard dismissal in SwiftUI (without using UIKit at all :) that I've implemented in my recent project PillsMemo.

Method 1: Adding a Toolbar with a Done Button

The first approach is straightforward: add a toolbar with a "Done" button that appears above the keyboard. This is particularly useful for keyboard types that don't include a return key, such as the numeric keypad.

struct DrugEditorView: View {

    enum Field: Hashable {
        case title
        case quantity
        case notes
    }

    @Bindable var drug: Drug
    @FocusState private var fieldIsFocused: Field?

    var body: some View {
        Form {
            Section(header: Text("Notes")) {
                    TextEditor(text: $drug.notes)
                        .focused($fieldIsFocused, equals: .notes)
                    .frame(minHeight: 70)
            }
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    fieldIsFocused = nil
                }
            }
        }
    }
}

Screenshot 1st method

This code adds a toolbar above the keyboard with a "Done" button aligned to the right. When tapped, it sets fieldIsFocused to nil, which dismisses the keyboard.

Key Points About This Method:

  • The .keyboard placement ensures the toolbar appears directly above the keyboard
  • The Spacer() pushes the "Done" button to the right side
  • Using a @FocusState property with an enum allows precise control over which field has focus (only available in iOS 15 and above)
  • Setting the focus state to nil dismisses the keyboard

Method 2: Dismissing When Tapping Outside

The second approach creates an invisible, tappable layer that dismisses the keyboard when users tap outside input fields. This solution uses a ZStack with Color.clear and contentShape:

@FocusState private var fieldIsFocused: Field?
var body: some View {
    ZStack {
        Form {
            Section(header: Text("Notes")) {
                TextEditor(text: $drug.notes)
                    .focused($fieldIsFocused, equals: .notes)
            }
            // ... other form elements
        }

        if fieldIsFocused != nil {
            Color.clear
                .contentShape(Rectangle())
                .onTapGesture {
                    fieldIsFocused = nil
                }
        }
    }
}

How This Works:

  • We wrap our form in a ZStack to create layering
  • We conditionally add an invisible layer (Color.clear) only when the keyboard is active
  • The contentShape(Rectangle()) ensures the invisible layer captures tap gestures
  • When tapped, it sets fieldIsFocused to nil, dismissing the keyboard