Reference — SwiftUI stacks, grids, outlines, and scroll enhancements through iOS 26
Provides SwiftUI container references for stacks, grids, outlines, and scroll views.
npx claudepluginhub charleswiltgen/axiomThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Stacks, grids, outlines, and scroll enhancements. iOS 14 through iOS 26.
Sources: WWDC 2020-10031, 2022-10056, 2023-10148, 2024-10144, 2025-256
| Use Case | Container | iOS |
|---|---|---|
| Fixed views vertical/horizontal | VStack / HStack | 13+ |
| Overlapping views | ZStack | 13+ |
| Large scrollable list | LazyVStack / LazyHStack | 14+ |
| Multi-column grid | LazyVGrid | 14+ |
| Multi-row grid (horizontal) | LazyHGrid | 14+ |
| Static grid, precise alignment | Grid | 16+ |
| Hierarchical data (tree) | List with children: | 14+ |
| Custom hierarchies | OutlineGroup | 14+ |
| Show/hide content | DisclosureGroup | 14+ |
VStack(alignment: .leading, spacing: 12) {
Text("Title")
Text("Subtitle")
}
HStack(alignment: .top, spacing: 8) {
Image(systemName: "star")
Text("Rating")
}
ZStack(alignment: .bottomTrailing) {
Image("photo")
Badge()
}
ZStack alignments: .center (default), .top, .bottom, .leading, .trailing, .topLeading, .topTrailing, .bottomLeading, .bottomTrailing
HStack {
Text("Left")
Spacer()
Text("Right")
}
Spacer(minLength: 20) // Minimum size
Render children only when visible. Use inside ScrollView.
ScrollView {
LazyVStack(spacing: 0) {
ForEach(items) { item in
ItemRow(item: item)
}
}
}
ScrollView {
LazyVStack(pinnedViews: [.sectionHeaders]) {
ForEach(sections) { section in
Section(header: SectionHeader(section)) {
ForEach(section.items) { item in
ItemRow(item: item)
}
}
}
}
}
Non-lazy grid with precise alignment. Loads all views at once.
Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 10) {
GridRow {
Text("Name")
TextField("Enter name", text: $name)
}
GridRow {
Text("Email")
TextField("Enter email", text: $email)
}
}
Modifiers:
gridCellColumns(_:) — Span multiple columnsgridColumnAlignment(_:) — Override column alignmentGrid {
GridRow {
Text("Header").gridCellColumns(2)
}
GridRow {
Text("Left")
Text("Right").gridColumnAlignment(.trailing)
}
}
Vertical-scrolling grid. Define columns; rows grow unbounded.
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns, spacing: 16) {
ForEach(items) { item in
ItemCard(item: item)
}
}
}
Horizontal-scrolling grid. Define rows; columns grow unbounded.
let rows = [GridItem(.fixed(100)), GridItem(.fixed(100))]
ScrollView(.horizontal) {
LazyHGrid(rows: rows, spacing: 16) {
ForEach(items) { item in
ItemCard(item: item)
}
}
}
| Size | Behavior |
|---|---|
.fixed(CGFloat) | Exact width/height |
.flexible(minimum:maximum:) | Fills space equally |
.adaptive(minimum:maximum:) | Creates as many as fit |
// Adaptive: responsive column count
let columns = [GridItem(.adaptive(minimum: 150))]
struct FileItem: Identifiable {
let id = UUID()
var name: String
var children: [FileItem]? // nil = leaf
}
List(files, children: \.children) { file in
Label(file.name, systemImage: file.children != nil ? "folder" : "doc")
}
.listStyle(.sidebar)
For custom hierarchical layouts outside List.
List {
ForEach(canvases) { canvas in
Section(header: Text(canvas.name)) {
OutlineGroup(canvas.graphics, children: \.children) { graphic in
GraphicRow(graphic: graphic)
}
}
}
}
@State private var isExpanded = false
DisclosureGroup("Advanced Options", isExpanded: $isExpanded) {
Toggle("Enable Feature", isOn: $feature)
Slider(value: $intensity)
}
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()
}
}
}
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(spacing: 16) {
ForEach(items) { item in
CarouselCard(item: item).frame(width: 280)
}
}
.padding(.horizontal)
}
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)
| Size | Scrollable? | Use |
|---|---|---|
| 1-20 | No | VStack/HStack |
| 1-20 | Yes | VStack/HStack in ScrollView |
| 20-100 | Yes | LazyVStack/LazyHStack |
| 100+ | Yes | LazyVStack/LazyHStack or List |
| Grid <50 | No | Grid |
| Grid 50+ | Yes | LazyVGrid/LazyHGrid |
Cache GridItem arrays — define outside body:
struct ContentView: View {
let columns = [GridItem(.adaptive(minimum: 150))] // ✅
var body: some View {
LazyVGrid(columns: columns) { ... }
}
}
ScrollView(.horizontal) {
LazyHStack {
ForEach(photoSets) { set in
ScrollView(.vertical) {
LazyVStack {
ForEach(set.photos) { PhotoView(photo: $0) }
}
}
}
}
}
Size views relative to scroll container.
ScrollView(.horizontal) {
LazyHStack {
ForEach(cards) { card in
CardView(card: card)
.containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 16)
}
}
}
Enable snapping.
ScrollView(.horizontal) {
LazyHStack {
ForEach(items) { ItemCard(item: $0) }
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
Track topmost visible item. Requires .id() on each item.
@State private var position: Item.ID?
ScrollView {
LazyVStack {
ForEach(items) { item in
ItemRow(item: item).id(item.id)
}
}
}
.scrollPosition(id: $position)
.scrollTransition { content, phase in
content
.opacity(1 - abs(phase.value) * 0.5)
.scaleEffect(phase.isIdentity ? 1.0 : 0.75)
}
.onScrollGeometryChange(for: Bool.self) { geo in
geo.contentOffset.y < geo.contentInsets.top
} action: { _, isTop in
showBackButton = !isTop
}
VideoPlayer(player: player)
.onScrollVisibilityChange(threshold: 0.2) { visible in
visible ? player.play() : player.pause()
}
WWDC: 2020-10031, 2022-10056, 2023-10148, 2024-10144, 2025-256
Docs: /swiftui/lazyvstack, /swiftui/lazyvgrid, /swiftui/lazyhgrid, /swiftui/grid, /swiftui/outlinegroup, /swiftui/disclosuregroup
Skills: axiom-swiftui-layout, axiom-swiftui-layout-ref, axiom-swiftui-nav, axiom-swiftui-26-ref
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.