Buttons become unresponsive after using .windowStyle(.plain) with auto-hiding menu

I'm developing a visionOS panorama viewer app where I need to implement an auto-hiding floating menu in immersive space. The menu should: Show for 3 seconds when entering immersive mode Auto-hide after 3 seconds, Reappear when user taps anywhere (using SpatialTapGesture). Buttons should respond to gaze + pinch interaction

The Problem:

When I add .windowStyle(.plain) to achieve transparent window background for the auto-hide effect, all buttons in the menu become completely unresponsive to gaze + pinch interaction. The buttons only respond to direct finger touch (poking).

Without .windowStyle(.plain): Buttons work correctly with gaze + pinch, but I cannot achieve transparent window background for hiding. With .windowStyle(.plain): Window can be transparent, but buttons lose gaze + pinch interaction.

Code:

App.swift:

@main
struct MyApp: App {
    @StateObject private var model = AppModel()

    var body: some Scene {
        WindowGroup(id: "MainWindow") {
            ContentView()
                .environmentObject(model)
        }
        .defaultSize(width: 900, height: 700)
        .windowResizability(.contentSize)
        .windowStyle(.plain)  // <-- This causes the interaction issue

        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
                .environmentObject(model)
        }
    }
}

ContentView.swift (simplified):

struct ContentView: View {
    @EnvironmentObject var model: AppModel
    @State private var isMenuVisible: Bool = true
    
    var body: some View {
        VStack {
            if model.isImmersiveViewActive {
                if isMenuVisible {
                    // This menu's buttons don't respond to gaze+pinch
                    immersiveControlMenu
                }
            } else {
                mainMenuButtons
            }
        }
        .glassBackgroundEffect()
    }
    
    private var immersiveControlMenu: some View {
        HStack {
            Button("Exit") {
                exitImmersiveSpace()
            }
            .buttonStyle(.bordered)  // Also tried .plain, same issue
        }
        .padding()
        .glassBackgroundEffect()
    }
}

ImmersiveView.swift:

struct ImmersiveView: View {
    @EnvironmentObject var model: AppModel
    
    var body: some View {
        RealityView { content in
            // Panorama sphere
            let sphere = ModelEntity(mesh: .generateSphere(radius: 1000), materials: [material])
            content.add(sphere)
            
            // Tap detector for menu toggle
            let tapDetector = Entity()
            tapDetector.components.set(CollisionComponent(shapes: [.generateSphere(radius: 900)]))
            tapDetector.components.set(InputTargetComponent())
            content.add(tapDetector)
        }
        .gesture(
            SpatialTapGesture()
                .targetedToAnyEntity()
                .onEnded { _ in
                    model.shouldShowMenu = true
                }
        )
    }
}

Environment: Xcode 26.2 visionOS 26.3 Vision Pro device

Questions:

  1. Is .windowStyle(.plain) expected to affect button interaction behavior?
  2. What is the recommended approach to achieve a transparent/hidden window in immersive mode while maintaining button interactivity?
  3. Is there an alternative to .windowStyle(.plain) for hiding window chrome in visionOS?

Thank you for any guidance!

Answered by Vision Pro Engineer in 874599022

Hey @Travel_Immersive,

No, .windowStyle(.plain) should not affect button interaction behavior.

In terms of creating a window that completely hides itself, I might suggest that you try a different approach. While you can have a window with no content and set the preferred visibility of the system controls to hidden, this is not the best approach as it still could leave the user with floating system UI that isn't attached to anything. Additionally, as this is a window that has system UI, the user could close this window at any time and you'd want to account for this.

It sounds like your experience might be better suited to using an ViewAttachmentComponent. Have you considered placing your immersiveControlMenu as the root view of a ViewAttachmentComponent in your immersive view? This way you can animate the visibility of this view and you fully control when and where this view is presented.

Let me know if you what you think,
Michael

Can you try commenting out your entity/SpatialTapGesture code? I have a hunch that the entity may be intercepting taps intended for the button. visionOS has some odd issues when we place gestures on entities that the user will be inside of.

You may want to take a look at SpatialEventGesture instead of using the tap in an entity. This will let you listen to input anywhere in the immersive space without using a specific entity.

Docs: https://developer.apple.com/documentation/swiftui/spatialeventgesture

Example Code: https://stepinto.vision/example-code/spatial-event-gesture/


Is .windowStyle(.plain) expected to affect button interaction behavior?

No, I've used buttons in many plain windows. Unless visionOS 26.3 introduced a new bug, it seems like something else is going on here.

What is the recommended approach to achieve a transparent/hidden window in immersive mode while maintaining button interactivity?

You're on the right track, see above about the entity gesture intercepting input.

Is there an alternative to .windowStyle(.plain) for hiding window chrome in visionOS?

No, not for hiding the glass background of the a window. .plain window style is the only way.

Hey @Travel_Immersive,

No, .windowStyle(.plain) should not affect button interaction behavior.

In terms of creating a window that completely hides itself, I might suggest that you try a different approach. While you can have a window with no content and set the preferred visibility of the system controls to hidden, this is not the best approach as it still could leave the user with floating system UI that isn't attached to anything. Additionally, as this is a window that has system UI, the user could close this window at any time and you'd want to account for this.

It sounds like your experience might be better suited to using an ViewAttachmentComponent. Have you considered placing your immersiveControlMenu as the root view of a ViewAttachmentComponent in your immersive view? This way you can animate the visibility of this view and you fully control when and where this view is presented.

Let me know if you what you think,
Michael

Buttons become unresponsive after using .windowStyle(.plain) with auto-hiding menu
 
 
Q