100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Swift

Stacks: VStack, HStack, and ZStack

How SwiftUI's three core layout containers arrange child views vertically, horizontally, and by depth, plus alignment and spacing controls.

Building UIs with SwiftUIBeginner8 min readJul 8, 2026
Analogies

Stacks: VStack, HStack, and ZStack

VStack, HStack, and ZStack are SwiftUI's foundational layout containers. VStack arranges its children top to bottom, HStack arranges them left to right (respecting right-to-left locales automatically), and ZStack layers children back to front along the z-axis, overlapping them at the same position. Nearly every SwiftUI screen is built by nesting these three containers, combined with spacing, alignment, and modifiers, to arrange more complex layouts than any single stack could express alone.

🏏

Cricket analogy: VStack arranges batting order top to bottom like a scorecard, HStack lines up fielders left to right along the boundary, and ZStack overlays the run-rate graphic on top of the live scoreboard at the same position.

Spacing and Alignment

Both VStack and HStack accept an alignment parameter (.leading, .center, .trailing for VStack; .top, .center, .bottom for HStack) and a spacing parameter controlling the gap between children. ZStack accepts a two-dimensional alignment (like .topLeading or .bottomTrailing) since it has no single natural axis. When no spacing value is given, SwiftUI uses a platform-appropriate default gap rather than zero, which surprises many newcomers who expect elements to sit flush against each other.

🏏

Cricket analogy: A VStack of the day's fall-of-wickets uses .leading alignment to left-align batsman names, while an HStack of the scoreboard's run tally uses .center with default spacing that surprises newcomers by not sitting flush.

swift
struct BadgeCard: View {
    var body: some View {
        ZStack(alignment: .topTrailing) {
            VStack(alignment: .leading, spacing: 12) {
                HStack {
                    Image(systemName: "star.fill")
                        .foregroundStyle(.yellow)
                    Text("Featured Course")
                        .font(.headline)
                }
                Text("SwiftUI Fundamentals")
                    .font(.title3.bold())
                Text("12 lessons \u{2022} 4h total")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            .padding()

            Text("NEW")
                .font(.caption2.bold())
                .padding(6)
                .background(.red, in: Capsule())
                .foregroundStyle(.white)
                .padding(8)
        }
        .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
    }
}

Nesting Stacks for Complex Layouts

Real layouts almost always nest stacks: an HStack of icon-and-label pairs inside a VStack of list rows, or a ZStack overlaying a badge on top of a VStack-based card, as in the example above. Because each stack is itself just a view conforming to View, there's no limit (besides readability and compiler type-checking time for very deeply nested @ViewBuilder expressions) to how deeply they can be composed.

🏏

Cricket analogy: A scorecard app nests an HStack of a batsman's name-and-runs pair inside a VStack of the full batting order, and a ZStack overlays a 'not out' badge on top of a VStack-based player card, just as real layouts nest stacks.

Stacks size themselves to fit their content by default (a 'hug' behavior), unlike UIKit's UIStackView, which can be configured with distribution and fill rules. To make a stack fill available space, apply .frame(maxWidth: .infinity) explicitly.

In a ZStack, later children are drawn on top of earlier ones. Forgetting this ordering is a common source of bugs when a badge or overlay unexpectedly appears behind its background.

  • VStack lays out children vertically, HStack horizontally, and ZStack layers them by depth.
  • alignment and spacing parameters control how children are positioned within VStack/HStack.
  • ZStack uses a two-dimensional alignment like .topTrailing since it has no single primary axis.
  • Stacks hug their content's size by default; use .frame(maxWidth: .infinity) to expand.
  • In ZStack, later-declared children render on top of earlier ones.
  • Complex layouts are built by nesting stacks inside one another, not through a single all-purpose container.

Practice what you learned

Was this page helpful?

Topics covered

#Swift#IOSWithSwiftUIStudyNotes#MobileDevelopment#StacksVStackHStackAndZStack#Stacks#VStack#HStack#ZStack#DataStructures#StudyNotes#SkillVeris