1

I'm encountering an issue where the same code for creating a UIBarButtonItem results in different visual appearances between iOS 18 (or earlier) and iOS 26 Beta 4. I'm testing on simulators and devices using Xcode 26 beta 4.

In my app, I'm setting a right bar button item in a view controller's navigation bar with the following code:

func initView() {
    self.view.backgroundColor = .systemGray6
    self.title = "Title"
    self.preferredContentSize = CGSize(width: 500, height: 600)
    let cancelButton = UIBarButtonItem.init(title: "Close", style: .plain, target: self, action: #selector(cancelAndBack))
    self.navigationItem.leftBarButtonItem = cancelButton
    if #available(iOS 26.0, *) {
        let doneButton = UIBarButtonItem.init(title: "Done", style: .prominent, target: self, action: #selector(cancelAndBack))
        self.navigationItem.rightBarButtonItem = doneButton
    } else {
        let doneButton = UIBarButtonItem.init(title: "Done", style: .done, target: self, action: #selector(cancelAndBack))
        self.navigationItem.rightBarButtonItem = doneButton
    }
    
}

For Cancel Button:

  • No explicit style is set here, so it defaults to .plain.
  • On iOS 18 and below, this appears as plain text without a background or rounded frame, which is the desired look.
  • On iOS 26 Beta 4, it shows with a white background and rounded corners, which I don't want. I need a clear background without any rounding or frame.

For Done Button:

  • I noticed that UIBarButtonItem.Style.done is deprecated in iOS 26 (as per documentation). So, I tried using .prominent explicitly, but the appearance is different ion IOS 26 in compared to iOS 18.
  • it is added system blue color as the background color of the button.

Question: Is there a recommended way to achieve consistent appearance across iOS 18 and iOS 26, specifically retaining the iOS 18 style (plain text, no background, no rounding) on iOS 26 devices? Are there any new APIs or configuration options in iOS 18 that I should use to override this default styling? Or is this a beta issue that might be resolved?

Fully Code:

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create the button
        let button = UIButton(type: .system)
        button.setTitle("Click me", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = .systemBlue
        button.layer.cornerRadius = 8
        
        
        // Add target for button tap
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        
        // Add button to view
        view.addSubview(button)
        
        // Set up constraints to center the button
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
    
    @objc func buttonTapped() {
        let exportViewController = ExportViewController()
        let navController = UINavigationController(rootViewController: exportViewController)
        navController.modalPresentationStyle = .formSheet
        
        self.present(navController, animated: true, completion: nil)
    }
}


import UIKit

class ExportViewController: UIViewController {
    
    
    func initView() {
        self.view.backgroundColor = .systemGray6
        self.title = "Title"
        self.preferredContentSize = CGSize(width: 500, height: 600)
        let cancelButton = UIBarButtonItem.init(title: "Close", style: .plain, target: self, action: #selector(cancelAndBack))
        self.navigationItem.leftBarButtonItem = cancelButton
        if #available(iOS 26.0, *) {
            let doneButton = UIBarButtonItem.init(title: "Done", style: .prominent, target: self, action: #selector(cancelAndBack))
            self.navigationItem.rightBarButtonItem = doneButton
        } else {
            let doneButton = UIBarButtonItem.init(title: "Done", style: .done, target: self, action: #selector(cancelAndBack))
            self.navigationItem.rightBarButtonItem = doneButton
        }
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Call initView first to set up the basic view
        initView()
        
        // Create and add the label
        let helloLabel = UILabel()
        if #available(iOS 26.0, *) {
            helloLabel.text = "Hello iOS 26"
        } else {
            helloLabel.text = "Hello iOS 18"
        }
        helloLabel.font = UIFont.systemFont(ofSize: 48)
        helloLabel.textAlignment = .center
        helloLabel.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(helloLabel)
        
        // Center the label in the view
        NSLayoutConstraint.activate([
            helloLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            helloLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
    
    @objc func cancelAndBack(){
        self.dismiss(animated: true, completion: nil)
    }
    
}

Please, refer attached screenshot for button appearance .

iOS 18 appearance iOS 26 appearance

2
  • 1
    You're asking if there's a recommended way, this is the recommended way. You're trying to solve a problem that doesn't actually exist. Commented Aug 4 at 7:59
  • Wait until you see all the other changes iOS 26 brings to the look and feel. If this bothers you, good luck. Commented Aug 29 at 2:28

1 Answer 1

11

You should not try to achieve a consistent appearance between iOS 18 and iOS 26, at least not in the long run. For now, there is the UIDesignRequiresCompatibility Info.plist key that you can set to YES. This opts out of the liquid glass of iOS 26, and the buttons would look the same as they did in iOS 18.

However, UIDesignRequiresCompatibility is temporary - it will be ignored in future versions. You should embrace the visual design of iOS 26 as soon as possible.


Just for fun:

You can remove the glass background by setting hidesSharedBackground to true. You can change the color of the text using setTitleTextAttributes.

e.g.

doneButton.hidesSharedBackground = true
doneButton.setTitleTextAttributes([.foregroundColor: UIColor.accent], for: .normal)
// UIColor.accent is the "AccentColor" color from the asset catalog

This gets pretty close to the iOS 18 appearance. You can also need to set the text color for other UIControl.States to achieve an even better reproduction.

Sign up to request clarification or add additional context in comments.

8 Comments

Yeah, Thanks a lot for your explanation. if i need to keep the glass effect as it (hidesSharedBackground = false), do you have idea how we can can change the glass effect colors on particular item ? When i use .prominent style, glass effect color is blue. do we have control for that ?
@DileepaChandrasekara Set the button's tintColor.
@DileepaChandrasekara As HangarRash said, you can change the glass color of a .prominent button just by setting doneButton.tintColor = UIColor.red. Otherwise, it will be the same color as your app's "AccentColor" color asset. For non-.prominent buttons, I don't think you can change their glass color.
@Sweeper thank you, hidesSharedBackground does help to remove that "bubble", but if you have multiple UIBarButtons in your navigationbar, the gap between the buttons is still bigger than on iOS 18. Is ther a way to remove that extra padding/insets?
@ahooahooo that is correct. As I said, you really shouldn’t be doing this in the first place. Embrace Liquid Glass! :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.