TechnologiesSwiftUI

ViewThatFits struct

iOSmacOStvOSwatchOSvisionOSiOS 16.0+✓ renders

A view that adapts to the available space by providing the first

How it works

ViewThatFits is a container that picks the first of several candidate views to fit in the space available along a given axis. You supply two or more alternatives in priority order, and SwiftUI measures each in turn against the proposed size, displaying the earliest one that doesn't overflow. Reach for it when a layout needs to gracefully degrade — a roomy presentation when there's space, a compact fallback when there isn't — without writing your own GeometryReader measurement or size-class branching.

  1. List candidates in priority order inside the content closure

    The trailing @ViewBuilder closure holds the alternatives, and ViewThatFits evaluates them top to bottom, choosing the first that fits the proposed size. Put your most expansive option first and your most compact last: here the full Label("Wide layout with full description", systemImage: "star.fill") is the preferred candidate, with the terse Label("Star", systemImage: "star.fill") as the fallback.

  2. Let the proposed size drive the selection

    ViewThatFits asks each candidate for its ideal size and compares it to the space its parent proposes, so the surrounding constraints decide which alternative wins. Both containers list the identical pair of labels; only the .frame(width: 300) versus .frame(width: 80) differs, which is exactly what flips the first ViewThatFits to the wide label and the second to the compact one.

  3. Restrict measurement to a single axis with the axes parameter

    The initializer takes an axes parameter (defaulting to both .horizontal and .vertical) that limits which dimensions must fit; pass .horizontal alone when only width is scarce, so a candidate that's tall but narrow still counts as fitting. The example relies on the default both-axes behavior, but because the constraint that varies is width via .frame, the horizontal measurement is what determines the outcome.

  4. Treat the result as a single view you can modify and compose

    ViewThatFits returns one opaque some View, so modifiers applied after it affect whichever candidate was chosen, and it slots into ordinary layout containers like any other view. The .padding() and .background(.blue.opacity(0.15), in: .rect(cornerRadius: 8)) chained onto each ViewThatFits, and their placement inside the VStack(spacing: 24), wrap the selected label rather than the alternatives that were rejected.

Try it — Change the second container's .frame(width: 80) to .frame(width: 300) and watch it switch from the compact Label("Star", ...) to the full "Wide layout with full description" label, since the wider proposal now lets the first candidate fit.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

ViewThatFits.swift
struct ViewThatFitsDemo: View {
    var body: some View {
        VStack(spacing: 24) {
            ViewThatFits {
                Label("Wide layout with full description", systemImage: "star.fill")
                Label("Star", systemImage: "star.fill")
            }
            .frame(width: 300)
            .padding()
            .background(.blue.opacity(0.15), in: .rect(cornerRadius: 8))

            ViewThatFits {
                Label("Wide layout with full description", systemImage: "star.fill")
                Label("Star", systemImage: "star.fill")
            }
            .frame(width: 80)
            .padding()
            .background(.green.opacity(0.15), in: .rect(cornerRadius: 8))
        }
        .padding()
    }
}
Live preview
Star Star
Star Star
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →