@ViewBuilder property wrapper allows to pass views as parameter to build custom views. It’s posible to create our own views like HStack or VStack.

In this example a custom sheet view receives a closure as parameter that provides the views that will be injected.

struct CustomSheetView<Content: View>: View {
    let content: Content
    
    init(i@ViewBuilder content: () -> Content) {        
        self.content = content()
    }
    
    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(Color(.displayP3, white: 0, opacity: 0.2))
            VStack(alignment: .leading) {
                Spacer()
                VStack(alignment: .leading) {
                    content // Here the completion injects the views
                }
                .padding(20)
                .frame(maxWidth: .infinity, minHeight: 500)
                .background(Color(.displayP3, white: 0.95, opacity: 1))
                .cornerRadius(25, corners: [.topLeft, .topRight])
            }
        }
    }
}

Then this custom view can take views as the rest of the swiftui components.

struct ExampleView: View {
    var body: some View {
        CustomSheetView {
            Text("My Title")
            Text("My Description")
        }
    }
}

Sometimes we just want to simplify the logic of our views. In this case we can create a method that returns some View.

private extension HeaderView {
    @ViewBuilder func makeEditButton() -> some View {
        if isEditing {
            CloseButton()
        } else {
            EditButton()
        }
    }
}

And then use the method to inject the view removing the logic and increasing the readibility.

struct HeaderView: View {
    var body: some View {
        HStack  {
            Title("My title")
            makeEditButton()
            ...
        }
    }
}