Describe the bug
.sizeThatFits layout renders SwiftUI views at their minimum compressed size instead of their ideal intrinsic size. Text gets truncated, views with flexible layout collapse, and the resulting snapshot is too small to show the actual content.
To Reproduce
@MainActor
@Suite(.snapshots(record: .missing), .serialized)
struct SizeThatFitsBugTests {
@Test func simpleText() {
let view = Text("Hello, World!")
.padding()
assertSnapshot(of: view, as: .image(layout: .sizeThatFits))
}
@Test func viewWithSpacer() {
let view = HStack {
Text("Left")
Spacer()
Text("Right")
}
.padding()
assertSnapshot(of: view, as: .image(layout: .sizeThatFits))
}
}
Expected behavior
Snapshot images sized to the view's ideal content size — text fully visible, flexible layouts expanded to their natural width.
Screenshots
| Simple Text |
With Spacer |
 |
 |
There's an image there, I swear!
Environment
- swift-snapshot-testing version: 1.19.1
- Xcode: 26.3
- Swift: 6.0
- OS: iOS 26.3.1 (iPhone 17 simulator)
Additional context
Why it's broken
The .sizeThatFits code path in SwiftUIView.swift (line 76-77) calls:
let maxSize = CGSize(width: 0.0, height: 0.0)
config.size = hostingController.sizeThatFits(in: maxSize)
UIHostingController.sizeThatFits(in:) interprets the CGSize as a layout proposal — not a request for intrinsic size. Passing CGSize.zero means "you have zero space available," so the hosting controller returns the view's minimum compressed size (truncated text, collapsed spacers). This is correct behavior from UIHostingController.
The fundamental problem is that CGSize cannot express "unspecified" dimensions. SwiftUI's ProposedViewSize supports nil for width/height (meaning "use your ideal size"), but there's no CGSize equivalent. So there's no value you can pass to UIHostingController.sizeThatFits(in:) that means "ideal size":
| Proposal |
Meaning |
Result |
CGSize.zero |
Minimum size |
Compressed/truncated content |
CGSize(.infinity, .infinity) |
Maximum size |
Spacer() expands unbounded |
CGSize(screenWidth, .infinity) |
Phone-width constrained |
Works, but device-dependent |
Quick fix
Replace the zero proposal with a screen-width-constrained one:
let screenWidth = UIScreen.main.bounds.width
let proposed = CGSize(width: screenWidth, height: .greatestFiniteMagnitude)
config.size = hostingController.sizeThatFits(in: proposed)
| Simple Text |
With Spacer |
 |
 |
This matches how Xcode's .previewLayout(.sizeThatFits) behaves — it proposes the device width and lets height wrap content. Verified working locally. The trade-off is that the output becomes device-dependent.
Proper fix: use ImageRenderer instead of UIHostingController
The current rendering pipeline goes through UIKit:
- Wrap SwiftUI view in
UIHostingController
- Call
sizeThatFits(in:) (CGSize — can't express "ideal")
- Add to
UIWindow, layout
- Capture via
view.layer.render(in:) / UIGraphicsImageRenderer
ImageRenderer (iOS 16+) renders SwiftUI views directly and has proposedSize: ProposedViewSize which supports nil dimensions:
let renderer = ImageRenderer(content: view)
renderer.scale = UIScreen.main.scale
// ProposedViewSize with nil dimensions = "use your ideal size"
// This is exactly what .sizeThatFits should mean
renderer.proposedSize = ProposedViewSize(width: nil, height: nil)
let image = renderer.uiImage
| Simple Text |
With Spacer |
 |
 |
ProposedViewSize(width: nil, height: nil) is the SwiftUI-native way to ask "what's your ideal size?" — the exact semantic that .sizeThatFits intends but can't achieve through UIHostingController.sizeThatFits(in:).
This would also simplify the rendering pipeline by removing the UIHostingController → UIWindow → layer.render chain entirely.
Describe the bug
.sizeThatFitslayout renders SwiftUI views at their minimum compressed size instead of their ideal intrinsic size. Text gets truncated, views with flexible layout collapse, and the resulting snapshot is too small to show the actual content.To Reproduce
Expected behavior
Snapshot images sized to the view's ideal content size — text fully visible, flexible layouts expanded to their natural width.
Screenshots
There's an image there, I swear!
Environment
Additional context
Why it's broken
The
.sizeThatFitscode path inSwiftUIView.swift(line 76-77) calls:UIHostingController.sizeThatFits(in:)interprets theCGSizeas a layout proposal — not a request for intrinsic size. PassingCGSize.zeromeans "you have zero space available," so the hosting controller returns the view's minimum compressed size (truncated text, collapsed spacers). This is correct behavior fromUIHostingController.The fundamental problem is that
CGSizecannot express "unspecified" dimensions. SwiftUI'sProposedViewSizesupportsnilfor width/height (meaning "use your ideal size"), but there's noCGSizeequivalent. So there's no value you can pass toUIHostingController.sizeThatFits(in:)that means "ideal size":CGSize.zeroCGSize(.infinity, .infinity)Spacer()expands unboundedCGSize(screenWidth, .infinity)Quick fix
Replace the zero proposal with a screen-width-constrained one:
This matches how Xcode's
.previewLayout(.sizeThatFits)behaves — it proposes the device width and lets height wrap content. Verified working locally. The trade-off is that the output becomes device-dependent.Proper fix: use
ImageRendererinstead ofUIHostingControllerThe current rendering pipeline goes through UIKit:
UIHostingControllersizeThatFits(in:)(CGSize — can't express "ideal")UIWindow, layoutview.layer.render(in:)/UIGraphicsImageRendererImageRenderer(iOS 16+) renders SwiftUI views directly and hasproposedSize: ProposedViewSizewhich supportsnildimensions:ProposedViewSize(width: nil, height: nil)is the SwiftUI-native way to ask "what's your ideal size?" — the exact semantic that.sizeThatFitsintends but can't achieve throughUIHostingController.sizeThatFits(in:).This would also simplify the rendering pipeline by removing the
UIHostingController→UIWindow→layer.renderchain entirely.