Skip to content

SwiftUI Containers Reference ​

A reference for SwiftUI container views: stacks, grids, outlines, custom containers, and scroll enhancements from iOS 13 through iOS 27.

When to Use This Reference ​

Use this reference when you're:

  • Choosing the right container for a layout (stack vs lazy stack vs grid vs List)
  • Fixing a list or grid that scrolls slowly and needs lazy loading
  • Building hierarchical or outline UI (trees, sidebars, disclosure rows)
  • Writing a reusable custom container that decorates, sections, or configures its children
  • Adding scroll snapping, scroll position tracking, or scroll-driven effects
  • Adopting the iOS 27 container additions (drag-to-reorder, swipe-action coordination, or a per-subtree AsyncImage session)

Example Prompts ​

Questions you can ask your assistant that will draw from this reference:

  • "Which container should I use for a 500-item scrolling list?"
  • "How do I build a photo grid that adapts its column count to screen width?"
  • "How do I build a custom container that puts a divider between its children?"
  • "How do I add drag-to-reorder outside a List on iOS 27?"
  • "How do I coordinate swipe actions in a ScrollView + LazyVStack?"
  • "How do I make a horizontal carousel snap to each card?"

What's Covered ​

Stacks ​

  • VStack, HStack, ZStack (and its nine alignments), Spacer
  • LazyVStack, LazyHStack, pinned section headers

Grids ​

  • Grid and GridRow (iOS 16+), gridCellColumns(_:), gridColumnAlignment(_:)
  • LazyVGrid, LazyHGrid
  • GridItem.Size: .fixed, .flexible, .adaptive

Outlines ​

  • List with children:, OutlineGroup, DisclosureGroup

Performance ​

  • When to use lazy containers, and caching GridItem arrays outside body
  • iOS 26 list loading and update improvements; nested lazy stacks that defer loading
  • Heavy rows: through iOS 26, neither LazyVStack nor List frees a visited row's state

Scroll Enhancements ​

  • containerRelativeFrame, scrollTargetLayout, scrollTargetBehavior, scrollPosition(id:) (iOS 17+)
  • scrollTransition
  • onScrollGeometryChange, onScrollVisibilityChange (iOS 18+)

Custom Containers (iOS 18+) ​

  • Declared vs resolved subviews
  • Group(subviews:), ForEach(subviews:), SubviewsCollection, Subview
  • Group(sections:), ForEach(sections:), SectionConfiguration
  • ContainerValues + @Entry for container-specific modifiers
  • Anti-patterns: [Data] row closures, AnyView inspection, PreferenceKey for per-child config

iOS 27 Additions ​

  • reorderable() and reorderContainer(for:move:) for drag-to-reorder in any container
  • swipeActionsContainer() and the onPresentationChanged: swipe callback
  • asyncImageURLSession(_:) for a per-subtree AsyncImage session

Documentation Scope ​

This page documents the containers-ref skill (in the axiom-swiftui suite). The full patterns, code, and gotchas live in the skill, which your assistant loads on demand.

Quick Decision ​

Use CaseContaineriOS
Fixed views vertical/horizontalVStack / HStack13+
Overlapping viewsZStack13+
Large scrollable listLazyVStack / LazyHStack14+
Multi-column gridLazyVGrid14+
Multi-row grid (horizontal)LazyHGrid14+
Static grid, precise alignmentGrid16+
Hierarchical data (tree)List with children:14+
Custom hierarchiesOutlineGroup14+
Show/hide contentDisclosureGroup14+
Custom container that styles its childrenGroup(subviews:) / ForEach(subviews:)18+
Custom container with sectionsGroup(sections:) / ForEach(sections:)18+
Container-specific modifier on childrenContainerValues + @Entry18+

When to Use Lazy ​

SizeScrollable?Use
1–20NoVStack/HStack
1–20YesVStack/HStack in ScrollView
20–100YesLazyVStack/LazyHStack
100+YesLazyVStack/LazyHStack or List
Grid <50NoGrid
Grid 50+YesLazyVGrid/LazyHGrid

Common Patterns ​

The skill leaves spacing: out on purpose: omitting it gives system spacing, the right default. The photo grid is the one deliberate exception.

Photo Grid ​

swift
// Near-zero gutters so the images read as a contact sheet
let columns = [GridItem(.adaptive(minimum: 100), spacing: 2)]

ScrollView {
    LazyVGrid(columns: columns, spacing: 2) {
        ForEach(photos) { photo in
            AsyncImage(url: photo.thumbnailURL) { image in
                image.resizable().aspectRatio(1, contentMode: .fill)
            } placeholder: { Color.gray }
            .aspectRatio(1, contentMode: .fill)
            .clipped()
        }
    }
}
swift
ScrollView(.horizontal, showsIndicators: false) {
    LazyHStack {
        ForEach(items) { item in
            CarouselCard(item: item).frame(width: 280)
        }
    }
    .padding(.horizontal)
}

File Browser ​

swift
List(selection: $selection) {
    OutlineGroup(rootItems, children: \.children) { item in
        Label {
            Text(item.name)
        } icon: {
            Image(systemName: item.children != nil ? "folder.fill" : "doc.fill")
        }
    }
}
.listStyle(.sidebar)
  • swiftui-layout-ref – Adaptive layout across device sizes, and the lazy container gotchas behind heavy rows
  • swiftui-layout – Decides which layout approach fits before you pick a container
  • swiftui-nav-ref – Navigation containers such as NavigationStack and NavigationSplitView
  • swiftui-26-ref – Other SwiftUI APIs new in iOS 26
  • hig – How much space to put between things, which this reference leaves to design
  • swiftui-gestures – Custom drag handling when swipe actions outside List aren't available
  • swiftui-performance-analyzer – Scans for janky scrolling, missing lazy containers, and excessive view updates

Resources ​

WWDC: 2020-10031, 2022-10056, 2023-10148, 2024-10144, 2024-10146, 2025-256, 2026-321

Docs: /swiftui/lazyvstack, /swiftui/lazyvgrid, /swiftui/lazyhgrid, /swiftui/grid, /swiftui/outlinegroup, /swiftui/disclosuregroup, /swiftui/creating-custom-container-views, /swiftui/containervalues, /swiftui/view/swipeactionscontainer(), /swiftui/view/asyncimageurlsession(_😃, /swiftui/dynamicviewcontent/reorderable(), /swiftui/reordering-items-in-lists-stacks-grids-and-custom-layouts

Released under the MIT License