SwiftUI Popover clips in iOS18

When you try to present medium height popover from the bottom of iPhone view then popover is clipped in iOS18 but works in old devices

Sample code

Button("Show Popover") {
            showPopover.toggle()
        }
        .popover(
            isPresented: $showPopover,
            arrowDirection: arrowDirection
        ) {
            conent
        }

Result

Please file a bug report via Feedback Assistant. After filing the bug report, please include the bug number here.

I have two FB13876192 FB13858544

I believe this is because the behaviour of the arrowEdge parameter (which has a default value of .top which shows the popover below) in popover(isPresented:attachmentAnchor:arrowEdge:content:) changed with the iOS 18 SDK. In iOS 17, it is used as a hint and is ignored if the content doesn’t fit, while on iOS 18 it is always used. There is a new popover(isPresented:attachmentAnchor:content:) modifier available on iOS 18 which automatically chooses an edge, but this isn’t always available when the minimum deployment target is <iOS 18 and thus is not the overload selected by the complier.

You can work around it with this extension, where the compiler will select the new modifier on the iOS 18 branch and the old one on the other one.

extension View {
    
    @ViewBuilder func autoEdgePopover<Content: View>(
        isPresented: Binding<Bool>,
        attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),
        @ViewBuilder content: @escaping () -> Content
    ) -> some View {
        if #available(iOS 18, *) {
            self
                .popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, content: content)
        } else {
            self
                .popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, content: content)
        }
    }
    
}

Thanks for providing the solution, I was wondering what's the root cause, didn't realize the new API that causing this.

quick adding the additional func with Item: Identifiable

@ViewBuilder public func autoEdgePopover<Item: Identifiable, Content: View>(
        item: Binding<Item?>,
        attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),
        @ViewBuilder content: @escaping (Item) -> Content
    ) -> some View {
        if #available(iOS 18, *) {
            self
                .popover(item: item, attachmentAnchor: attachmentAnchor, content: content)
        } else {
            self
                .popover(item: item, attachmentAnchor: attachmentAnchor, content: content)
        }
    }
SwiftUI Popover clips in iOS18
 
 
Q