I have a regular SwiftUI View embedded inside of a NavigationStack. In this view, I make use of the .searchable() view modifier to make that view searchable. I have a button on the toolbar placed on the .confirmationAction section, which is a problem when a User types into the search bar and the button gets replaced by the SearchBar's cancel button.
Thus, I conditionally place the button, depending on whether a User is searching, either on the navigationBar or on the keyboard. The latter does not work however, as the button does not show and when trying to debug the View Hierarchy, Xcode throws an error saying the View Hierarchy could not be displayed. If I set the button to be on the .bottomBar instead, it shows up perfectly and the View Hierarchy also displays with no further issue.
Has someone come across this issue and if so, how did you get it fixed?
Thank you in advance.
SwiftUI - Placing ToolbarItem on .keyboard does not work
I have a similar issue and haven't found any solution yet. It is obviously a problem with iOS 17 because on iOS 16 it used to work as expected.
Can either of you post some sample code to show the problem? I tested on iOS 17 and iOS 16.4 with this code and saw the same behavior of the keyboard button only showing up for the TextField and not in .searchable, but am unsure if I am replicating it correctly. Either way, this is definitely worth a feedback report (at https://feedbackassistant.apple.com) and please post the FB number here! If you can attach a small sample project to the feedback report, that would help a lot. Thank you!
This is the code I tested with:
struct ContentView: View {
@State private var text: String = ""
@State private var searchText: String = ""
var body: some View {
NavigationStack {
TextField("Test TextField", text: $text)
.toolbar {
ToolbarItem(placement: .keyboard) {
Button("TestButton") {
//code
}
}
}
}
.searchable(text: $searchText)
}
}
I have a sample project showing the missing toolbar items on .keyboard placement:
https://github.com/MortenGregersen/KeyboardBarTest
It also contains a video showing the issue.
The issue is also present in apps in the App Store build with Xcode 14.
I have submitted a feedback with all the details: FB13209435
Similar thing is happening in a project im running, but simulator is working fine but on device isnt which is really strange as there the same devices and same software version
I have the same problem. Simulator works as expected and the keyboard button shows, but when I test the build on a device it isn't visible.
If the toolBar is placed in a view that's inside a NavigationStack it doesn't work and this is a bug.
Thanks for all of your responses, this is a known issue with no supported workaround. Please keep filing feedback reports if you have not already, thank you!
There is a workaround! The solution may not for work for everyone but at least it is worth a try. I had to show (and hide) a sheet right after entring the view. Miraculously the toolbar starts to appear after that. Be advised that this code requires iOS 16.4 and above. If you remove .presentationBackground(.clear) it is available for lower targets.
struct YourView: View {
@State var isShowingAWorkAround = true
var body: some View{
HSTack {
// you code here
}
.sheet(isPresented: $isShowingWorkAround) {
TemporarySheet {
self.isShowingAufmass = false
} resetCallback: {
self.isShowingWorkAround = false
}.presentationBackground(.clear)
}
}
}
Code for TemporarySheet
struct TemporarySheet: View {
let dismissCallback: (() -> Void)
let resetCallback: (() -> Void)
var body: some View {
Text("").onAppear {
self.dismissCallback()
}.onDisappear {
self.resetCallback()
}
}
}
Sure you can take anything instead Text("").
Tested on iOS 17.2 public beta (which has identical problem as 17.1).
I have the same issue on iOS 17. The ToolbarItem works on a physical device when debugging through Xcode, but does not work on the physical device.
I have the same issue (IOS 17).
https://gist.github.com/JamesSedlacek/2d0425319e2a854da8c51f4b05c9842a
Here's the workaround I'm using right now.
Experiencing the same issue. Toolbar works fine in simulator, but does not show up on physical device. However, if I open the view, move the app to the background and then move it back to the foreground again, the toolbar suddenly works as expected.
Is your button in an HStack with a Spacer? I used .frame(maxWidth: .infinity, alignment: .trailing) instead and it showed for me.
It's been couple months already and still there is no solution to this problem? Unbelievable!
same problem here
The problem still exists. It seems that the toolbar becomes visible after the first submit.
I am also seeing a variety of this problem - the toolbar appears, but there's no content in the toolbar. Code is below but the TL;DR is the same as F99's response above, removing the Spacer() from the HStack fixes the problem
HStack {
TextField(store.prompt, text: $input)
.hideableToolbar(show: store.showToolbar) {
ToolbarItemGroup(placement: .keyboard) {
HStack {
ForEach(fastList) { item in
Button {
//
} label: {
Text("\(item.name)")
}
}
Spacer() // <–– COMMENTING OUT THIS LINE FIXES THE PROBLEM
}
}
}
}
}
ToolbarItem placement .keyboard for UITextView is not working. I had it in .bottombar and was working but now when keyboard appears the toolbar at the bottom disappears. So it does not work for both .bottombar and .keyboard for UITextView. .keyboard should work even for UITextView-UIRepresentableView as under the hood UIKit detects becomeFirstResonder(). So no idea why it is suddenly not working. So the only option is to use the input accessory view or have your own custom toolbar at the bottom which feels like back to beginning of SwiftUI.
Any news here @Vision Pro Engineer?
Any have a reliable workaround?
I'm able to reproduce the problem on iOS 18 using Xcode 16. Moving the app to the background and then switching back to it will make the tool bar appear.
Thank you!
Having a similar issue: FB15588827
same issue iOS 18
Hello, has anyone found a solution for this?
Here's my code:
VStack(spacing: 8) {
TextField("",
text: $amountFormatter.value,
onEditingChanged: { amountFormatter.isEditing = $0 })
.accessibilityLabel(Text(amountFormatter.voiceOverAmountLabel))
.font(.bodyRegularL)
.foregroundStyle(Color.typographyText)
.keyboardType(.decimalPad)
.showClearButton($amountFormatter.value, addTopPadding: false)
.keyboardDoneButton()
.onChange(of: amountFormatter.value) { _ in
amountFormatter.validateValue()
}
.onChange(of: isFocused) { isFocused in
amountFormatter.updateValue(isEditing: isFocused)
print(isFocused)
}
.focused($isFocused)
Rectangle().frame(height: 1)
.foregroundStyle(Color.standardMain500)
}
}
And the modifier:
func keyboardDoneButton() -> some View {
modifier(KeyboardDoneButtonViewModifier())
}
}
private struct KeyboardDoneButtonViewModifier: ViewModifier {
@FocusState var isFocused: Bool
func body(content: Content) -> some View {
content
.focused($isFocused)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
if isFocused {
Spacer()
Button(L10n.menuDoneButtonText) {
isFocused = false
}
}
}
}
}
}
Still an issue as of Feb 2025 with Xcode 16.2.
That's actually crazy it's still an issue on iOS 18. Anyone checked if iOS 26 fixes this?
This can happen if you're using NavigationStack in your app and you enter a view without using it, for example I was making a form appear in a .sheet{}, and if I did something like this the toolbar wouldn't work on any TextField inside the .sheet:
.sheet(isPresented: $showUploadSheet, content: {
PhotoUploadView()
})
But if I wrapped it in a NavigationStack like this, then it would start working.
.sheet(isPresented: $showUploadSheet, content: {
NavigationStack {
PhotoUploadView()
}
})
One last thing is that this method does not work if you use a .fullScreenCover{} instead of a .sheet{}
I'm not sure why, it would be nice if it did.