Architecture • 18 August 2026 • Written by Lochan Chugh

SwiftUI Container Values: Passing Metadata to Custom Layouts

SwiftUI Container Values: Passing Metadata to Custom Layouts

SwiftUI Container Values: Passing Metadata to Custom Layouts

SwiftUI provides two main ways to pass data through the view tree: Environment Values (which pass data down to child views) and Preferences (which pass data up to parent views). However, both have limitations when building custom layout containers. Environment values apply globally to a hierarchy, and preferences require complex reduction logic that can trigger redundant layout passes.

SwiftUI addresses this parent-child coordination problem with Container Values. Introduced with the @Entry macro, this type-safe property storage allows custom layout containers to inspect and arrange subviews based on metadata declarations attached directly to individual children.


Defining Container Values

To declare a custom metadata key, extend the ContainerValues structure using the @Entry macro to define a default value:

import SwiftUI

extension ContainerValues {
    // Developer Thoughts: The @Entry macro synthesizes 
    // the underlying ContainerValueKey boilerplate.
    @Entry var priority: Int = 0
    @Entry var isSpacer: Bool = false
}

Once defined, you can attach these properties to subviews within your container using the .containerValue modifier:

struct TaskBoard: View {
    var body: some View {
        CustomFlexStack {
            Text("High Priority Task")
                .containerValue(\.priority, 100) // Attach custom metadata
            
            Text("Standard Task")
                .containerValue(\.priority, 1)
            
            Color.clear
                .containerValue(\.isSpacer, true)
        }
    }
}

Reading Values Inside Custom Layout Containers

When building a custom container, you can read these values directly from the subview proxies.

This custom layout uses containerValues to sort elements by priority before placing them in the layout bounds:

struct CustomFlexStack<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        Group(subviews: content) { subviews in
            // Developer Thoughts: subviews is a Collection of Subview proxies.
            // We can read containerValues directly without subscribing to preference updates.
            let sortedSubviews = subviews.sorted {
                $0.containerValues.priority > $1.containerValues.priority
            }
            
            VStack {
                ForEach(sortedSubviews) { subview in
                    subview
                        .padding(subview.containerValues.isSpacer ? 0 : 8)
                }
            }
        }
    }
}

Summary

Container Values provide a direct, parent-scoped metadata channel that avoids the performance costs of preference keys. They are evaluated synchronously during the layout pass and do not propagate past the immediate parent container. Keep in mind that container values are discarded if the child view is not placed inside a custom container that explicitly checks for those properties.

References & Further Reading

Ready for more depth?

Master these concepts with our structured technical roadmap.

View Roadmap