Back to blog

Working with Stacks in SwiftUI


Aasif Khan
By Aasif Khan | Last Updated on October 6th, 2022 6:32 am | 4-min read

You use stacks in SwiftUI to group views together. You can choose from the VStack, HStack and ZStack, and combine them to build complex layouts. In this tutorial, you’ll learn how to use stack views with SwiftUI.

What we’ll discuss:

  • How to use VStack, HStack and ZStack
  • Approaches to position views within stacks
  • How to use alignment and spacing parameters
  • Building complex views by combining stacks

What’s a Stack?

A stack is a collection of SwiftUI views that are grouped together. You can use 3 kinds of stacks with SwiftUI:

  1. VStack, a vertical stack, which shows views in a top-to-bottom list
  2. HStack, a horizontal stack, which shows views in a left-to-right list
  3. ZStack, a depth-based stack, which shows views in a back-to-front list

Here’s a visual example:

You can compare stacks in SwiftUI with UIStackView in UIKit. Stacks are static, so they’re different from List and table views, for example. Like other SwiftUI views, stacks can contain a maximum of 10 subviews. You can, of course, combine VStacks, HStacks and ZStacks to create complex User Interfaces.

The VStack groups subviews together vertically, along the vertical axis, so top-to-bottom. The HStack fits in the same category; it’s the same as a VStack, except it groups subviews left-to-right along the horizontal axis.

The ZStack is in a category of its own, because it groups views together along the z- or depth axis, shown back-to-front. Views in a ZStack can overlap, which means it’s ideal for creating UI stacks that overlay other views. A button or Text view onto a background Image view, for example.

Makes you wonder why they didn’t call it an XStack or DStack…

VStack, HStack and ZStack in SwiftUI

Let’s see how stacks work in SwiftUI. Here’s an example of a VStack with 3 Text views:

VStack {
Text(“Zen and The Art of Motorcycle Maintenance”)
Text(“Robert M. Pirsig”)
Text(“1974, 418 pages”)
}

As you can see in the screenshot above, the Live Preview in Xcode shows 3 Text views organized vertically – top-to-bottom – in a VStack. The first Text view in the VStack corresponds to the first line of text, shown on the right in the Preview.

It’s important to note here that the default alignment for stacks is centered both horizontally and vertically. The Text views, however, are aligned leading, i.e. left-to-right in this part of the world.

Let’s move on to the HStack. The next code is wholly unsurprising…

HStack {
Text(“Reinder de Vries”)
Image(“reinder”)
}

See how the 2 subviews of the HStack are neatly organized horizontally and left-to-right? They’re centered in both axes by default. Neat!

Next up, the ZStack. As we’ve discussed before, the ZStack will group views together back-to-front, along the depth axis (Z). Views will overlap each other.

Check this out:

ZStack {
Image(“ocean-background”)
Text(“A journey of a thousand miles\nstarts with a single step”)
}

In the above screenshot, you can see how a bit of text overlays a background image. This is the ZStack: views are shown on top of each other. Comparing the SwiftUI code and the screenshot, you can infer that the order is back-to-front. The first view in the ZStack is shown at the back of the stack, behind the others.

Author’s Note: I’ve omitted a few modifiers in the ZStack code example, for brevity. You can see them in the screenshot. You can learn more about modifiers here: Create UIs with Views and Modifiers in SwiftUI

Stack Layout with Alignment and Spacing

Stacks in SwiftUI have 2 important attributes: their alignment and spacing. Because stacks follow a box-like layout system, it’s essential that you can position the stack’s subviews as you see fit.

When creating a VStack or HStack, you can provide a value for the alignment and/or spacing parameters. Like this:

VStack(alignment: .center, spacing: 5) {

}
The alignment parameter takes values from the HorizontalAlignment and VerticalAlignment structs, for VStack and HStack respectively. In the initializer functions, both the alignment and spacing parameters are optional – you can include both, either or none.

The spacing parameter determines the amount of space or “margins” between subviews in a stack, in points. The value’s type is Double, but you can also provide integer values.

It’s counter-intuitive, but VStacks are aligned on the horizontal axis, and HStacks on the vertical axis. The width and height are the same as the size of the largest subview in the stack.

You’ve got a few options to align VStack and HStack:

  • HStack:
    • .top – “stick” views to the top of the stack
    • .bottom – stick ’em to the bottom of the stack
    • .center – align subviews in the middle (default)
    • .firstTextBaseline and .lastTextBaseline, see below
  • VStack:
    • .leading – align views to the left (LTR)
    • .center – align them in the middle (default)
    • .trailing – align views to the right (LTR)
  • ZStack:
    • Combine horizontal/vertical: .leading + .bottom
    • Add them as one: .leadingBottom

The ZStack does have an alignment attribute as well. You can either use a combination of horizontal and vertical alignments, such as .topLeading (top-left corner), or use both separately, like this:

ZStack(horizontal: .leading, vertical: .bottom) {
// Views are aligned starting in the bottom-left of the stack
}

The .firstTextBaseline and .lastTextBaseline options, for the HStack, seem odd, but they’re super useful. It allows you to align Text views inside a stack with each other, based on the first or last view. This essentially aligns the views with the text inside them, as opposed to the view’s edges.

A great approach to align, position and space out views with SwiftUI is to make use of the Spacer view. You can learn more about that here: Create UIs with Views and Modifiers in SwiftUI

Combining Stacks with SwiftUI

The real power of stacks in SwiftUI lies in combining them. You can build pretty elaborate views pretty quickly coding combinations of VStack, HStack and ZStack.

Here, check this out:

HStack {
ZStack {
Image(“gradient”)
Circle()
}
VStack(alignment: .leading, spacing: 4) {
Text(“Zen and The Art of Motorcycle Maintenance”)
Text(“Robert M. Pirsig”)
Text(“1974, 418 pages”)
}
}

Again, I’ve omitted modifiers for brevity. You can spot ’em in the screenshot if you want to replicate the code exactly.

In the above code, we’ve combined HStack, ZStack and VStack to form a complete view. The HStack is the main element, which includes a ZStack and VStack. The HStack is easy to identify in the Preview – it’s the element with a left and a right, kinda like a row-and-column layout.

The ZStack consists of an image in the back, with a Circle view overlay. You can totally change this into something else of course, like some meta information that’s placed onto the image.

The VStack inside the HStack simply adds a few Text views above one another, in a list. They’re aligned to the left – or .leading, as iOS calls it, to account for left-to-right and right-to-left locales – and given a few points of vertical space between them.

When you’re designing and creating layouts for your iOS app, it’s smart to keep this box-like or row/column-like layout system in mind.

You just start drawing rectangles on screen, aligning them around an axis, and pressing stuff to the left or right with Spacer. It’s intuitive to build layouts this way, and you’ll get something tangible quite quickly. Awesome!

Further Reading

Stacks are a great way to build views and layouts with SwiftUI. In this tutorial we’ve discussed how you can use the VStack, HStack and ZStack with SwiftUI.


Aasif Khan

Head of SEO at Appy Pie

App Builder

Most Popular Posts