Background
I'm building a SwiftUI form (AddRecipeView) inside a NavigationStack. I’ve added a .toolbar(placement: .keyboard) with a “Done” button to dismiss the keyboard, especially useful for numberPad inputs.
However, the "Done" button does not appear the first time I enter this view and tap a TextField. After navigating away to some other tab and returning and hitting thre TextField again, the "Done" button shows up correctly. This behavior happens on both simulator and physical device (both tested with iOS 18.5, and XCode's version being 16.5).
Here's a simplified reproducible example, but if anyone wants to inspect the entire project, it can be found in this repo:
struct AddRecipeView: View { @State private var time: Int? = nil @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { Form { TextField("Time (minutes)", value: $time, formatter: NumberFormatter()) .keyboardType(.numberPad) } .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { UIApplication.shared.sendAction( #selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } } } } } Console output
When I hit on the TextField for the second time (once I have traveled to another tab and come back), I get these output console messages:
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID. inputModality = Keyboard, inputOperation = <null selector>, customInfoType = UIEmojiSearchOperations Invalid frame dimension (negative or non-finite). Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. ... "<NSAutoresizingMaskLayoutConstraint:0x6000021c7250 h=--& v=--& _UIToolbarContentView.width == 0 (active)>", "<NSLayoutConstraint:0x6000021aa6c0 H:|-(16)-[_UIButtonBarStackView:0x101480180] (active, names: '|':_UIToolbarContentView:0x1014a6090)>", "<NSLayoutConstraint:0x6000021a9e00 H:[_UIButtonBarStackView:0x101480180]-(16)-| (active, names: '|':_UIToolbarContentView:0x1014a6090)>" Will attempt to recover by breaking constraint <NSLayoutConstraint:0x6000021a9e00 H:[_UIButtonBarStackView:0x101480180]-(16)-| (active, names: '|':_UIToolbarContentView:0x1014a6090)> This seems like a layout bug—perhaps the _UIToolbarContentView is rendering with zero width until after a navigation cycle.
Things I’ve already tried:
Replaced placeholder views with .frame(width: 100, height: 44) to prevent zero-size issues
Used .submitLabel(.done) and @FocusState (but numberPad doesn’t support submit)
Applied the NavigationPath workaround using NavigationStack(path:) (from this post) — no luck
Question
Is this a known SwiftUI or UIKit bug in iOS 18? Is there a known way to ensure the keyboard toolbar appears correctly on first presentation?