SwiftUI - presentationDetents behaves incorrectly on iOS 16–18 but works correctly on iOS 26

I'm using a custom modifier called AutoSheetDetentModifier to automatically size a sheet based on its content.

On iOS 26, it works as expected: the content height is measured correctly and the sheet shrinks to match that height.

However, on iOS 16, 17 and 18, the same code doesn’t work. The content height is still measured, but the sheet does not reduce its height. Instead, the sheet remains larger and the content appears vertically centered. (Note that content() includes ScrollView)

public struct AutoSheetDetentModifier: ViewModifier {
    @State private var height: CGFloat = 380 // default value to avoid bouncing

    public func body(content: Content) -> some View {
        content
            .modifier(MeasureHeightViewModifier(height: $height))
            .presentationDetents([.height(height)])
    }
}

public struct MeasureHeightViewModifier: ViewModifier {
    @Binding var height: CGFloat
    
    public func body(content: Content) -> some View {
        content
            .fixedSize(horizontal: false, vertical: true)
            .background(
                GeometryReader { geo -> Color in
                    DispatchQueue.main.async {
                        height = geo.size.height
                    }
                    return Color.clear
                }
            )
    }
}

extension View {
    public func applyAutoSheetDetent() -> some View {
        self
            .modifier(AutoSheetDetentModifier())
    }
}
public var body: some View {
     VStack {
         header()
         content() // includes ScrollView
         footer()
     }
     .background(Color.customGray)
     .applyAutoSheetDetent()
}

func content() -> some View {
    ScrollView {
        VStack {
            ForEach(items) { item in
                itemRow(item)
            }
        }
    }
    .frame(maxHeight: UIScreen.main.bounds.height * 0.7)
}

Screenshot from iOS 26 (working as expected):

Screenshot from iOS 18 (not working):

How can I make .presentationDetents(.height) shrink the sheet correctly on iOS 16–18, the same way it does on iOS 26?

This is a very interesting post for sure.

The presentationDetents(:) modifier, which enables sheets to automatically adjust their height based on the content they contain, simplifies the creation of adaptive sheets without the need for custom modifiers or intricate calculations. However, it appears that the behavior of Detents(:) may differ in iOS 16 to 18, as you mentioned. This could be a result of the new UI or the behavior of the ScrollView.

While I appreciate the code you provided, I recommend posting a focused sample to enhance its clarity and usefulness.

If you are unfamiliar with preparing a test project, I suggest referring to the following resource: Creating a test project.

As a potential workaround, in my opinion, but interested in other developer's opinion, forcing a layout update or animation may assist iOS in recalculating the view sizes accurately.

.onChange(of: presented) { _ in
     (...) // Dispatch main thread
        UIView.animate(withDuration: 0) {
       
}

However I am looking forward to see your focused sample I can run in different iOS versions.

Albert Pascual
  Worldwide Developer Relations.

SwiftUI - presentationDetents behaves incorrectly on iOS 16–18 but works correctly on iOS 26
 
 
Q