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

Sigh, it's still not fixed today. Im so sick of SwiftuI.

Not fixed in Xcode 16 beta 3

Any news on Xcode 16 alpha version?

any update?

Based on my testing, it seems that the bug with .disabled() has been fixed on iOS 18.1 and 18.2.

The build environment was Xcode 16.1 with Swift 5.10.

It also worked on iOS18.0

I noticed if the Button's title is dynamic it breaks .disabled() from working, e.g.

Button("Save \(text)") { // dynamic title
items.append(ListItem(text: text))
}
.disabled(text.isEmpty) // no worky anymore

Xcode 16.2, iOS simulator 18.2

Submitted FB16539507 to request the .alert() docs be updated to state if using .disabled is supported because currently it is not mentioned. Also included this bug I noticed which is probably a waste of time since I reported the bug to the documentation team.

It's wild that this same bug is still present 2 years later.

When using .disabled:

  • iOS 16 (.7.10) - Button is not visible
  • iOS 17 (.4.1) - First time the alert is shown action doesn't get called, 2nd time it works
  • iOS 18 (.1.1) - Works

Cool iOS 18 works, but what about other versions?

Disabled button in SwiftUI .alert not working
 
 
Q