Loading...

How to change the window level to floating, popUpMenu, etc. in SwiftUI?

question swiftui swift
Ram Patra Published on February 19, 2025

When developing macOS applications with SwiftUI, you might need to create floating windows that stay on top of other windows. While modern macOS versions (15+) make this straightforward with the .windowLevel(.floating) modifier, supporting older versions requires a different approach. In this post, I’ll show you how to create floating windows that work across different macOS versions.

The Modern Approach (macOS 15+)

For the latest macOS versions, setting a window level is as simple as adding a modifier:

.windowLevel(.floating)

However, this won’t work on older versions of macOS. Let’s look at a more compatible solution.

The Cross-Version Solution

To support older macOS versions, we need to access the underlying NSWindow and set its level manually. Here’s how to do it:

First, create a bridge to access the NSWindow:

import AppKit
import SwiftUI

struct WindowAccessor: NSViewRepresentable {
    var callback: (NSWindow?) -> Void
    
    func makeNSView(context: Context) -> NSView {
        let view = NSView()
        DispatchQueue.main.async {
            self.callback(view.window)
        }
        return view
    }
    
    func updateNSView(_ nsView: NSView, context: Context) {
        // No update needed
    }
}

Then, use this accessor in your SwiftUI view:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("This window will float!")
                .padding()
        }
        .background(
            WindowAccessor { window in
                if let window = window {
                    window.level = NSWindow.Level.popUpMenu
                }
            }
            .frame(width: 0, height: 0)
        )
    }
}

How It Works

  1. The WindowAccessor creates an NSView that can access its parent window
  2. We use DispatchQueue.main.async to ensure the window is available when we try to access it
  3. The callback provides us with the NSWindow instance
  4. We set the window’s level to .popUpMenu to make it float above regular windows
  5. The zero-sized frame ensures our accessor view doesn’t affect the layout

Window Level Options

You can use different window levels depending on your needs:

// Common window levels
window.level = NSWindow.Level.normal        // Regular window
window.level = NSWindow.Level.floating      // Floating window
window.level = NSWindow.Level.popUpMenu     // Menu level
window.level = NSWindow.Level.modalPanel    // Modal dialog level
window.level = NSWindow.Level.screenSaver   // Screen saver level

Complete Example

Here’s a complete example of a floating window with some content:

import SwiftUI
import AppKit

struct FloatingWindowView: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("Floating Window")
                .font(.title)
            
            Text("This window will stay on top of other windows")
                .multilineTextAlignment(.center)
            
            Button("Close") {
                NSApplication.shared.keyWindow?.close()
            }
        }
        .frame(width: 300, height: 200)
        .padding()
        .background(
            WindowAccessor { window in
                if let window = window {
                    window.level = NSWindow.Level.floating
                    window.title = "Floating Window"
                }
            }
            .frame(width: 0, height: 0)
        )
    }
}

Best Practices

  1. Choose the appropriate window level for your use case
  2. Consider user experience - floating windows can be intrusive
  3. Provide a way to close or minimize the floating window
  4. Test on different macOS versions to ensure compatibility

This approach gives you a reliable way to create floating windows (windows that always stay on top of other windows) that work across different macOS versions while maintaining a clean SwiftUI-style implementation.

Remember that floating windows should be used judiciously - they can be disruptive to the user’s workflow if overused. Consider whether your use case really requires a window to float above others before implementing this feature.

Presentify

Take your presentation to the next level.

FaceScreen

Put your face and name on your screen.

ToDoBar

Your to-dos on your menu bar.

Ram Patra Published on February 19, 2025
Image placeholder

Keep reading

If this article was helpful, others might be too

question swiftui iOS April 2, 2024 How to force an app or a view to open in landscape only mode in iOS using SwiftUI?

In SwiftUI, you can force an app to open in landscape mode by configuring the supported interface orientations in your app’s target settings. Here’s a step-by-step guide to configuring interface orientations in Xcode:

question swiftui swift August 31, 2024 @Published in SwiftUI

In SwiftUI, the @Published property wrapper is used in combination with the ObservableObject protocol to automatically announce changes to properties of a class. This allows SwiftUI views that depend on these properties to update automatically when the data changes.

question swiftui swift September 2, 2024 Combine in SwiftUI and how you can rewrite the same code using async await

Combine is Apple’s declarative framework for handling asynchronous events and data streams in Swift. Introduced in SwiftUI and iOS 13, Combine leverages reactive programming principles, allowing developers to process values over time and manage complex asynchronous workflows with clarity and efficiency.

Like my work?

Please, feel free to reach out. I would be more than happy to chat.