Search code examples
macosswiftuialert

SwiftUI - MacOS - TextField within Alert not receiving focus


I've added a TextField within an Alert in MacOS. However, the TextField doesn't receive focus, when the alert shows. Here's the code I've tested with. Is this even possible? If this is a bug, then please suggest other workarounds.

import SwiftUI

struct ContentView: View {
    @State private var presented = false
    @State private var username = ""
    @FocusState private var focused: Bool
    
    var body: some View {
        VStack {
            Button(action: {
                focused = true
                presented = true
            }, label: {
                Text("Click to show Alert")
            })
        }
        .alert("", isPresented: $presented, actions: {
            VStack {
                TextField("User name (email address)", text: $username)
                    .focusable()
                    .focused($focused)
                Button(action: {}, label: { Text("OK") })
            }
            .onAppear() {
                // Try setting focus with a delay.
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
                    focused = true
                })
            }
        }, message: {
            Text("The textField in this alert doesn't get the focus. Therefore, a manual click is needed to set focus and start typing.")
        })
    }
}

Solution

  • I can confirm that focus doesn't work inside Alert. A possible workaround is using a custom Sheet:

    struct ContentView: View {
        @State private var presented = false
        @State private var username = ""
        @FocusState private var focused: Bool
    
        var body: some View {
            VStack {
                Button(action: {
                    presented = true
                    focused = true
                }, label: {
                    Text("Click to show Sheet")
                })
            }
            
            .sheet(isPresented: $presented, content: {
                
                VStack {
                    // App Icon placeholder
                    RoundedRectangle(cornerRadius: 8)
                        .fill(.secondary)
                        .frame(width: 48, height: 48)
                        .padding(12)
                    
                    Text("The textField in this alert doesn't get the focus. Therefore, a manual click is needed to set focus and start typing.")
                        .font(.caption)
                        .multilineTextAlignment(.center)
    
                    TextField("User name (email address)", text: $username)
                        .focused($focused)
                        .padding(.vertical)
                    
                    Button(action: {
                        presented = false
                    }, label: {
                        Text("OK")
                            .frame(maxWidth: .infinity)
                    })
                    .buttonStyle(.borderedProminent)
                }
                .padding()
                .frame(width: 260)
            })
        }
    }