How to read window snapping state and classification
We can use the surfaceSnappingInfo environment value to access window snapping data.
Overview
Starting in visionOS 26, users can snap windows to vertical surfaces like walls and doors. We can read surfaceSnappingInfo data from the environment. There are two useful bits of information.
Is the window snapped
We can use the isSnapped property to tell if the current window is snapped or not. We can use this to adapt the window or content to this new state. For example, in Looming Deadlines I have a window focus mode that hides all window controls. I could activate that automatically when a window is snapped.
struct Example083: View {
@Environment(\.surfaceSnappingInfo) private var surfaceSnappingInfo
var body: some View {
Text("\(surfaceSnappingInfo.isSnapped ? "Yes" : "No")")
}
}It is important to use this in a view, not at the app level or a scene context. We can access this value with no extra work.
Classification
We can also read the ARKit surface classification. For example, visionOS will tell us if a surface is a wall or a door. To access this data, we need to add two values to the project plist file. Set UIWantsDetailedSurfaceInfo to YES and set NSWorldSensingUsageDescription with a string that describes why the app needs access to this data.

<key>UIWantsDetailedSurfaceInfo</key>
<true/>
<key>NSHandsTrackingUsageDescription</key>
<string>World and plane detection access is needed to explore the ARKit example code</string>
<key>UIApplicationSceneManifest</key>With those values set we can access classification. The first time the app tries to read this value the user will be prompted to grant permission. We can check to see if the window has been snapped and if access has been granted. Then we can switch on the classification values or look for a specific value.
.onChange(of: surfaceSnappingInfo) {
if (!surfaceSnappingInfo.isSnapped && SurfaceSnappingInfo.authorizationStatus == .authorized) {
switch surfaceSnappingInfo.classification {
case .wall:
print("Snapped to a wall")
case .door:
print("Snapped to the door")
default:
print("Snapped to something else: \(surfaceSnappingInfo.classification?.description ?? "" )")
}
}
}
Caveats and Gotchas
- The list of classifications is pretty short, limiting us to a few options.
- Windows can only snap to vertical surfaces. I’d love to be able to snap to horizontal surfaces like we can with widgets.
- Classification doesn’t always update correctly when moving a window. For example, I can snap to a closed door. When I drag the window on the wall that includes the door, sometimes the value gets set to “wall” and sometimes it gets set to “none”.
- When running a compiled app on device, snapped windows are automatically locked and a padlock symbol is shows. When running a your app from Xcode, the window controls for snapping may look a bit different. The lock symbol is missing and the option to lock a window in place is missing (as of Beta 1).

Video Demo
Full Example Code
struct Example083: View {
@Environment(\.surfaceSnappingInfo) private var surfaceSnappingInfo
var body: some View {
VStack(spacing: 12) {
Spacer()
Text("Surface Snapping")
.font(.extraLargeTitle)
VStack(spacing: 12) {
HStack {
Text("Is Snapped:")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .trailing)
Text("\(surfaceSnappingInfo.isSnapped ? "Yes" : "No")")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .leading)
}
HStack {
Text("Classification:")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .trailing)
Text("\(surfaceSnappingInfo.classification?.description ?? "" )")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
Spacer()
}
.onChange(of: surfaceSnappingInfo) {
if (!surfaceSnappingInfo.isSnapped && SurfaceSnappingInfo.authorizationStatus == .authorized) {
switch surfaceSnappingInfo.classification {
case .wall:
print("Snapped to a wall")
case .door:
print("Snapped to the door")
default:
print("Snapped to something else: \(surfaceSnappingInfo.classification?.description ?? "" )")
}
}
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Follow Step Into Vision