How to get the frame or insets of the new iPadOS 26 window control buttons (close, minimize, fullscreen)?

In iPadOS 26, Apple introduced macOS-style window control buttons (close, minimize, fullscreen) for iPad apps running in a floating window. I'm working on a custom toolbar (UIView) positioned near the top of the window, and I'd like to avoid overlapping with these new controls.

However, I haven't found any public API that exposes the frame, layout margins, or safe area insets related to this new UI region. I've checked the window's safeAreaInsets, additionalSafeAreaInsets, and UIWindowSceneDelegate APIs, but none of them seem to reflect the area occupied by these buttons.

Is there an officially supported way to:

  • Get the layout information (frame, insets, or margins) of the window control buttons on iPadOS 26?
  • Or, is there a system-defined guideline or padding value we should use to avoid overlapping this new UI?

Any clarification or guidance would be appreciated!

You should consider adopting standard controls like UIBarButtonItem. They work out the box and respect the system preferences.

Alternative you could take a look at UIWindowScene.Geometry to get the window scene’s geometry

I have the same question. WWDC Sessions and the HIG mention "moving your controls" when the window control appears. It's great that this happens automatically when using a standard NavigationStack and standard toolbar, however for apps that are unable to use standard UI elements, the documentation currently makes it sound like there is some way to get this sizing programmatically.

Filed FB18559686

Screenshot of the issue:

Sample code to make this happen:

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0) {
            HStack {
                
                // Trying to make this button respect window controls safe area
                Button(action: { }, label: {
                    Image(systemName: "xmark")
                })
                .padding()
                .foregroundStyle(.primary)
                .glassEffect()
                
                
                Spacer()
            }
            .padding()
            .background(.fill.quaternary)
            Rectangle()
                .foregroundStyle(.fill.quinary)
        }
    }
}

#Preview {
    ContentView()
}

Things I found out:

In your UIWindowSceneDelegate use:

@available(iOS 26.0, *)
func preferredWindowingControlStyle(for windowScene: UIWindowScene) -> UIWindowScene.WindowingControlStyle {
        return .minimal
}

This way the window controls will move closer to the top and the safe area is adjusted so your button should move to below the window controls.

If you don't want that the safe area is adjusted (which will result in more white space at the top), you can use .unified instead of .minimal. In UIKit you can then use a layout guide to place a view below the window controls:

let contentGuide = self.view.layoutGuide(for: .margins(cornerAdaptation: .vertical))
childView.topAnchor.constraint(equalTo: contentGuide.topAnchor).isActive = true

You can also use .horizontal and .leftAnchor to place the view to the right of the window controls.

I don't know how to do this in SwiftUI.

That is interesting and promising that there is something for it in UIKit. Hopefully we get something for it in SwiftUI.

@Mobiel I was able to use your example to create a UIKit → SwiftUI connection where those layout guide values are available to a SwiftUI view. It works okay. You can see here the red box is in SwiftUI, and it is detecting where the window control is.

There is one issue, which is that when the window is returned to full screen, the layout guide is not updating to "0" size for the window control. Not sure if that's an iPadOS beta bug or what.

Here is a screenshot:

Here is the code:

//
//  ContentView.swift
//  WindowControlsTest
//
//  Created by MAK on 8/7/25.
//

import SwiftUI
import UIKit

struct ContentView: View {
    @State var offsets = WindowControlDetection()

    var body: some View {
        ZStack(alignment: .topLeading) {
            WindowControlsUIKitViewRepresentable()
                                           
            Rectangle()
                .foregroundStyle(.red)
                .frame(width: offsets.leadingInset, height: offsets.topInset)
            
            Rectangle()
                .hidden()
                .overlay {
                    Text("leading: \(Int(offsets.leadingInset))  top: \(Int(offsets.topInset))")
                }
        }
        .ignoresSafeArea()
        .environment(offsets)
    }
}

@Observable class WindowControlDetection {
    var leadingInset: CGFloat = 0
    var topInset: CGFloat = 0
}

class WindowControlsUIKitView: UIView {
    private let offsets: WindowControlDetection
    
    init(offsets: WindowControlDetection) {
        self.offsets = offsets
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        let newLeading = layoutGuide(for: .margins(cornerAdaptation: .horizontal)).layoutFrame.minX
        let newTop = layoutGuide(for: .margins(cornerAdaptation: .vertical)).layoutFrame.minY
        
        DispatchQueue.main.async { [weak offsets] in
            offsets?.leadingInset = newLeading
            offsets?.topInset = newTop
        }
    }
}

struct WindowControlsUIKitViewRepresentable: UIViewRepresentable {
    @Environment(WindowControlDetection.self) var layoutOffsets
    
    func makeUIView(context: Context) -> WindowControlsUIKitView {
        return WindowControlsUIKitView(offsets: layoutOffsets)
    }
    
    func updateUIView(_ uiView: WindowControlsUIKitView, context: Context) { }
}

I found that I could use the containerCornerInsets on the GeometryProxy to get this frame. (https://developer.apple.com/documentation/swiftui/geometryproxy/containercornerinsets)

Here is my code where I added a red rectangle behind the controls.

GeometryReader { geo in
    NavigationSplitView(columnVisibility: $sceneModel.columnVisibility) {
       
        GPSidebarView(appModels: self.appModels())
            .sceneWidth(geo.size.width)
        
    } detail: {
        ZStack(alignment: .topLeading) {
            GPRootContentViewIOS26(appModels: self.appModels())
                .cardStackVisible(sceneModel.hasCardOnMainStack)
            
            Rectangle()
                .fill(.red)
                .frame(width: geo.containerCornerInsets.topLeading.width, height: geo.containerCornerInsets.topLeading.height)
                .ignoresSafeArea()
        }
    }
} 

When I added this with the red rectangle here is what I get for the red rectangle.

Then when my iPad app goes full screen I get

How to get the frame or insets of the new iPadOS 26 window control buttons (close, minimize, fullscreen)?
 
 
Q