Search code examples
swiftmacosswiftuinswindow

Removing title bar (including traffic lights and title) in a SwiftUI desktop application


I'm currently developing a SwiftUI desktop application and I'm facing an issue with window customization. I want to entirely remove the title bar from my application's window - this includes the traffic lights (close, minimize, maximize buttons) and the title.

Here is a simplified version of my current SwiftUI application structure:

@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            MainView()
        }.windowStyle(HiddenTitleBarWindowStyle())
        .commands {
            CommandGroup(replacing: .windowArrangement) { }
        }
    }
}

In MyApp, I'm using HiddenTitleBarWindowStyle(), but it's not giving me the expected result. The application's window still has the title bar with traffic lights and title visible.

I'm aware that customization of the NSWindow instance could allow me to control the window's appearance, but it's unclear to me how to do that in the context of a SwiftUI application that starts from the @main struct.

Can anyone guide me on how to completely remove the title bar in my SwiftUI desktop application?

Thanks in advance.


Solution

  • here is a demo for hiding the buttons and title bar using swiftui on macos. note: NSWindow is still nil during .onAppear. as an alternative you can access it after the app launches by responding to user input (option 1), or during app launch via AppDelegate (option 2).

    Option 1 -- responding to button press

    struct ContentView: View {
        var body: some View {
            ZStack {
                Color.clear
                Button {
                    chromeless()
                } label: {
                    Text("go chromeless")
                }
            }
        }
    }
    
    func chromeless() {
        if let window = NSApp.windows.first {
            //hide buttons
            window.standardWindowButton(.closeButton)?.isHidden = true
            window.standardWindowButton(.miniaturizeButton)?.isHidden = true
            window.standardWindowButton(.zoomButton)?.isHidden = true
            
            //hide title and bar
            window.titleVisibility = .hidden
            window.titlebarAppearsTransparent = true
        }
    }
    

    Option 2 -- At app launch

    Based on this answer you can also hide the window chrome at app launch.

    final class AppDelegate: NSObject, NSApplicationDelegate {
        func applicationDidFinishLaunching(_ notification: Notification) {
            chromeless()
        }
    }
    
    @main
    struct AlreadyMacOSApp: App {
        @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }