feat(iOS): support UIBarButtonItem in header
Description
The current implementation of headerLeft and headerRight adds a react view as a custom view in a UIBarButtonItem. This implementation is sufficient at most times but I believe we can achieve greater "native feel" if the native stack has an protocol for adding actual UIBarButtonItems in the header. As the UIBarButtonItems has properties and features that can be difficult to mimic with a react view.
Also with the introduction of iOS 26, using only custom views in UIBarButtonItem presents some limitations. Mainly that the adaptive tint color (based on the underlying view) is not working on a UIBarButtonItem with a custom view as demonstrated below under "Screenshots".
Changes
This PR adds the properties headerRightBarButtonItems and headerLeftBarButtonsItems on the native stack Screen that makes it possible to add one or several UIBarButtonItem to the right/left of the header. Most of the features of the UIBarButtonItem is supported (see either "Bar Button Items" in the example apps or the type definition).
Screenshots / GIFs
Non adaptive tint color when using old property headerRight on iOS 26
https://github.com/user-attachments/assets/194c70b5-7492-48df-aa2c-8fb889ece461
Adaptive tint color when using new property headerRightBarButtonItems on iOS 26
https://github.com/user-attachments/assets/9acb1981-3461-4f28-8a0d-54ea9956d3c0
UIBarButtonItem with style "prominent" on iOS 26
UIBarButtonItem with UIMenu on iOS 26
https://github.com/user-attachments/assets/db2f7bab-3ade-423f-b80b-9c35b6cee578
Test code and steps to reproduce
I've created a screen named "Bar Button Items" in the example app that showcases all of the proposed features.
Checklist
- [x] Included code example that can be used to test this change
- [x] Updated TS types
- [ ] Updated documentation:
- [ ] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md
- [ ] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md
- [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx
- [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx Unsure if I need to do this. I'm targeting react-navigation v6 and above so no JS changes has been made to react-native-screens in this PR. Would appreciate some guidance to if and where I should make documentation changes if needed. Thank you!
- [ ] Ensured that CI passes
Related PR in react-navigation: https://github.com/react-navigation/react-navigation/pull/12657
i like this
Hey! This is really promising. We're working currently on support for iOS 26 etc. and we're doing general overhaul of the lib. As of now, we're not sure what will be the API shape & scope, therefore I won't review it for now. Once we settle the internal discussion I'll revisit your implementation. I'm sure we'll be able to land it in some form.
Hey! This is really promising. We're working currently on support for iOS 26 etc. and we're doing general overhaul of the lib. As of now, we're not sure what will be the API shape & scope, therefore I won't review it for now. Once we settle the internal discussion I'll revisit your implementation. I'm sure we'll be able to land it in some form.
I'm really glad you liked it! Yeah I saw that you have done a bunch of iOS 26 related PRs and changes to the API so I understand that my suggestion may not match the shape you are targeting. Please let me know if there are any changes I can do right now and I will happily do them asap. I truly believe something like this would be awesome for react-native-screens when iOS 26 is out of beta.
Hi Great stuff. We're looking at your PR and would like to merge the changes soon. Here are some comments from me, and I believe @kkafar wants to look more closely in the following days.
Also, please update the PR with changes from main branch. There could be some conflicts.
Thank you! I've updated the PR with changes from main and resolved all conflicts
Hey, I most likely won't find time tomorrow & I'm going for a two week PTO on Thursday. I'll try to review this as one of first things after I'm back from PTO.
:sorry:
Hey, I most likely won't find time tomorrow & I'm going for a two week PTO on Thursday. I'll try to review this as one of first things after I'm back from PTO.
:sorry:
Hey! No worries! Have a nice PTO 😊
@kmichalikk I added support for systemImage (using SF Symbols) in this commit https://github.com/software-mansion/react-native-screens/pull/2987/commits/8981d6a77a8a83d3f09ce1e25d4316f79d333cc9 Feel free to take a look or try it out whenever you have the chance. Thanks!
@kmichalikk refactored everything a bit in https://github.com/software-mansion/react-native-screens/pull/2987/commits/af27795c0535b85ac75c8cf679ed2181b5af6f31
I realised that users might want to combine native UIBarButtonItems and React Nodes in the header left and right. So renamed headerRightBarButtonItems and headerLeftRightBarButtonItems to headerRightItems and headerLeftItems. These two properties now accepts an array containing either dicts for UIBarButtonItems or functions returning a React Node. The new functionality is shown in the screen "ReactNodeButtonDemo".
I wasn't able to properly run this probably because of some issues with linking to react-navigation PR - buttons were not displayed at all. I'll try again later. In the meantime I have two small nitpicks.
My bad! I forgot to push my latest commits to react-navigation. Should be working now
@kmichalikk I added support for hidesSharedBackground: boolean when rendering custom React Elements. Making it possible to show them without the liquid glass effect (see screenshot below). Feel free to have a look and try it out!
I tested this and it seems to fix several UI issues on iOS 26. Thank you @johankasperi ! 🙏
@kkafar @kmichalikk is there any chance this might be released in the next few days? 😇 We need this to get our app ready for iOS 26 with a deadline in mid September. 🙈
I tested this and it seems to fix several UI issues on iOS 26. Thank you @johankasperi ! 🙏
@kkafar @kmichalikk is there any chance this might be released in the next few days? 😇 We need this to get our app ready for iOS 26 with a deadline in mid September. 🙈
Thank you! Don't know your circumstances for the deadline but wanted to share that you can opt out from the new design with UIDesignRequiresCompatibility in your Info.plist
Thank you! Don't know your circumstances for the deadline but wanted to share that you can opt out from the new design with UIDesignRequiresCompatibility in your Info.plist
Apple is considering our App for featuring. So, opting out is no an option for us. :/
Thank you! Don't know your circumstances for the deadline but wanted to share that you can opt out from the new design with UIDesignRequiresCompatibility in your Info.plist
Apple is considering our App for featuring. So, opting out is no an option for us. :/
I understand. Congrats for being considered for featuring!
I wanna update you, that I'm starting to look at this PR 😅 I can't say however we'll be able to land in in just couple of days, since it's a bit chunky.
Remember that you always have patch-package at your disposal (know that it is kinda clunky solution, but if forced to - may be a way to go).
I wonder what is going on with the shadow beneath the bar button items, that disappears after few seconds. @kligarski is that something you experienced when testing iOS 26?
I noticed some unusual shadow behavior with the search bar in the header but I did not pay much attention to it yet as there were more critical bugs with the search bar that could've been impacting the shadows.
Okay, I'll create ticket for this to test it out on pure native app, to verify whether this is UIKit issue or something on our end.
I wonder what is going on with the shadow beneath the bar button items, that disappears after few seconds. @kligarski is that something you experienced when testing iOS 26?
I haven't noticed that! I almost hope it's a bug in iOS 26 because I haven't written any code (as far as I know) that should affect that. But good catch!
It is happening on the back button in other demo screens and in the News app from apple. So I'm guessing its part of UIKit
https://github.com/user-attachments/assets/70d592d5-374e-47f0-937e-9fe242c93f28
https://github.com/user-attachments/assets/6996593c-a136-455f-a23c-62069a74a66a
Okay. This looks really good. I have few initial remarks. Please answer them.
Thanks for the review! I think I have adressed all of your remarks. Please let me know if you have any further questions or if there is anything else I should take a look at.
This PR seems promising! Can't wait! Any ETA?
This needs priority now that iOS26 is released. Just updated Xcode and now all my IconButtons aren't aligned correctly anymore in the headers.
This needs priority now that iOS26 is released. Just updated Xcode and now all my IconButtons aren't aligned correctly anymore in the headers.
Sorry been stuck with more important bugs in my app. Plan is to adress/fix everything from the latest review tomorrow (Sept 17th). But want to remind you that you can opt-out from the new iOS 26 design in your app with this flag https://github.com/software-mansion/react-native-screens/pull/2987#issuecomment-3257998157
⚠️ No. 4
I'm unable to reproduce this using a single custom view as property to headerRight (copy/pasted your code and running in iPhone 16 Pro). For me the custom view is shown in the header. I also have to put a regular UIBarButton item in the array for the excessive items menu to appear.
Either way, React Elements or custom viesw is not rendered in the excessive items context menu. But if you put to many regular UIBarButtonItems the menu will work as expected:
https://github.com/user-attachments/assets/0c4ae908-a668-421f-aa16-3e83527e5a60
Added an example of this here: https://github.com/software-mansion/react-native-screens/pull/2987/commits/882aea244c412efa0e208ec60adf40a5d7b852f1
⚠️ No. 1 - Notice that the header title appears only after a delay when using spacing. I haven't observed that in other screens.
Good catch! No idea why this is happening. It is not happening on iOS 26 though so I'm guessing it's something in UIKit?
⚠️ No.2 - Header
I am able to reproduce this on the main branch in the "Header Options"-example so don't think this is related to this PR. Should be fixed though but maybe should open a separate issue for this?
https://github.com/user-attachments/assets/c3af7a85-3227-48af-a24f-dd8b371139c5
🚫 No. 3 - POTENTIALLY BLOCKING
I don't think this is a regression. You have to set headerBackVisible: true to make the back button visible if you have defined headerLeft in the current implementation. Tested this on the main branch in the "Header Options" example by setting headerBackVisible: undefined and defining headerLeft.
🚫 / ⚠️ No. 5 (haven't made my mind whether it's blocking or not)
Don't think this is related to this PR either unfortunately. I am able to reproduce this on the main branch as well:
Also, isn't @t0maboro trying to fix this in https://github.com/software-mansion/react-native-screens/pull/3210?
@kkafar I think I have adressed everything you mentioned in the last review now. Please let me know if I have missed something or if there is something else I need to take a look at. Thank you!
Thank you so much!
Back on it. Will submit review / approval in few hours