Disabled button in SwiftUI .alert not working

I found an issue when implementing an alert with a TextField to input a name. I want the action button to be disabled until a name has been entered, but the action block is never executed when the button has become enabled and pressed. The problem seems to appear only when name is initially an empty string. Tested with iOS 17.0.

struct MyView: View {
  @State private var name = ""

  var body: some View {
    SomeView()
    .alert(...) {
      TextField("Name", text: $name)
      Button("Action") {
        // Action
      }.disabled(name.isEmpty)
      Button("Cancel", role: .cancel) {}
    }
  }
}


I encountered a similar issue at the release of iOS 16 which is when I filed a feedback report. At that time, buttons that were disabled didn't show up in the alert at all.

Then, sometime during the early iOS 17 betas (beta 4 maybe?), the issue was addressed and this was added to the SwiftUI release notes:

Resolved Issues

  • Fixed an issue where dynamically enabled buttons (e.g. with a TextField) were not updated in alerts. (95917673) (FB10463211)

I then had to test this to see if things were fixed, and the disabled buttons did show up…but the action closure wasn't called at all. I then filed another feedback report (FB12857555) and nothing has happened yet.

I suggest also filing feedback as that will help elevate the problem with Apple and hopefully get it fixed soon.

Definitely file a feedback report at https://feedbackassistant.apple.com as @BabyJ mentioned and post the number here as well. Thank you!

This issue is still not fixed, which is absolutely ridiculous. already starting to feel regret on wasting my time with this absolute shambles of a framework

For Apple engineer, I have opened a radar: FB13410286

@henrik273 thanks for confirming this is a SwiftUI bug - it's been driving me nuts for days.

It seems the button uses the initial disabled state upon tapping it, regardless of its current disabled state.

This is the only reliable work-around I've found:

  • set the initial state to be .disabled(isDisabled) where isDisabled is false.
  • set the text field to have some default text that the user must delete.
  • when the user deletes all the text, isDisabled becomes true.

The closure only gets called if the initial state is .disabled(false) rather than .disabled(true). Also, the alert must appear with .disabled(false) before you update to .disabled(true).

Another hack could be to use DispatchQueue to update .disabled(true) ~0.6 seconds later (so after the alert appears), but I wouldn't recommend this as it's not reliable.

I hope this helps whilst the bug is fixed.

Not fixed in Xcode 16 beta 1

Disabled button in SwiftUI .alert not working
 
 
Q