---
title: "SwiftUI Custom Alignment"
source: "/writing/swiftui-custom-alignment/"
---

Article

# SwiftUI Custom Alignment

Paul Himes

September 18, 2023

An animation of a three bookshelves. On the middle shelf, some books start to slide and fall over. A tiny robot pushes the books back into place.

_Updated for Xcode 14.3_

SwiftUI comes with many built-in options for aligning views. When you use the basic container views such as `HStack`, `VStack`, and `ZStack` you have the option to provide an alignment parameter which controls the placement of subviews relative to each other. Alignments are categorized as either `HorizontalAlignment` or `VerticalAlignment`.

A container's available alignments are those perpendicular to the predominant axis of the container view. For example, `HStack` lays out subviews horizontally, so it allows `VerticalAlignment`. `VStack` lays out subviews vertically, so it allows `HorizontalAlignment`. `ZStack` lays out subviews along both vertical and horizontal axes, so it uses a compound `Alignment` type which contains both a `HorizontalAlignment` and `VerticalAlignment`.

Each alignment type comes with a collection of standard alignments. For example, the standard alignments for `VerticalAlignment` are: `top`, `center`, `bottom`, `firstTextBaseline`, and `lastTextBaseline`.

Three VerticalAlignment diagrams for standard top, center, and bottom alignments.

Some Standard VerticalAlignments

These pre-defined alignments can be used to create most typical layout designs. But what if a design calls for views to be placed at a location other than one of the standard alignments?

A cyan ZStack with a "Hello, SwiftUI!" text label aligned to the leading edge and vertically centered at two-thirds the height of the container.

A Custom Alignment

For this, SwiftUI allows us to define our own custom alignments. Let's see how we can define a custom `VerticalAlignment` that places views two-thirds of the way down a `ZStack`.

## Custom Alignment Implementation

The built-in alignment options are defined as static properties on the corresponding alignment types. Here's how `VerticalAlignment` defines it's `top` alignment value.

extension VerticalAlignment {
    public static let top: VerticalAlignment
}

Let's define our two-thirds alignment in a similar way.

extension VerticalAlignment {
    public static let twoThirds = VerticalAlignment(...)
}

You'll notice we actually have to initialize a `VerticalAlignment` when we declare our custom alignment value. The initializer takes a single parameter of type `AlignmentID.Type`. We'll need to define an `AlignmentID` for our custom alignment. This type is never meant to be instantiated, so we'll define it as an `enum`.

enum TwoThirdsAlignmentId: AlignmentID {
    static func defaultValue(in context: ViewDimensions) -> CGFloat {
        ...
    }
}

The `AlignmentID` protocol requires a single static function named `defaultValue(in:)`. This function contains our custom layout calculations. It receives a `ViewDimensions` value which provides sizing information about the `View` we're aligning. It's also responsible for returning an offset in the view's coordinate space. So returning `0` for a vertical alignment would align to the top edge of the view. Returning the height of the view would align to the bottom edge of the view. For our two-thirds alignment, we want to align to two-thirds of the view's height.

enum TwoThirdsAlignmentId: AlignmentID {
    static func defaultValue(in context: ViewDimensions) -> CGFloat {
        context.height * 2/3
    }
}

Now we can use our `AlignmentID` with our `VerticalAlignment`.

extension VerticalAlignment {
    public static let twoThirds = VerticalAlignment(TwoThirdsAlignmentId.self)
}

Since we want to use this custom alignment with a `ZStack`, there's one more static property to define. Remember that `ZStack` uses the `Alignment` type which combines a `VerticalAlignment` and a `HorizontalAlignment`. In this example, we'll use a leading horizontal alignment. So let's define a `twoThirdsLeading` alignment like this:

extension Alignment {
    static let twoThirdsLeading = Alignment(horizontal: .leading, vertical: .twoThirds)
}

## Using a Custom Alignment

Now we're ready to use our custom alignment in a `ZStack`. Let's start by building a SwiftUI `View` with a `ZStack` and some text content.

struct Example: View {
    var body: some View {
        ZStack {
            Color.cyan
            TitleView()
            RedLine()
        }
    }
}

A cyan ZStack with a "Hello, SwiftUI!" text label in the center. A horizontal red line crosses the center.

A Default ZStack

Our `ZStack` contains three views: a background `Color` view, a `TitleView`, and a `RedLine` view. The `Color` view expands the `ZStack` to use all available space. This will make it easier for us to see how the content views are being aligned. The `RedLine` view will also be used to show us exactly where views are being aligned vertically. By default, `ZStack` uses `center` alignment to place all content views in the center of the container. Let's see what happens when we use our new custom alignment.

struct Example: View {
    var body: some View {
        ZStack(alignment: .twoThirdsLeading) {
            Color.cyan
            TitleView()
            RedLine()
        }
    }
}

A cyan ZStack with a "Hello, SwiftUI!" text label aligned to the leading edge at two-thirds height. A horizontal red line crosses the ZStack at two-thirds of its height.

ZStack with Custom Alignment

Our custom alignment is working! We can see that all three content views are aligned to two-thirds of their heights. But there's one more change we need to make to match our original design. Rather than pinning the `TitleView` on the `RedLine` at two-thirds of its height, we actually want the `TitleView` to be centered vertically on the `RedLine`. To achieve this, we need to adjust how `TitleView` responds to our custom `VerticalAlignment.twoThirds` alignment. This can be done with SwiftUI's `alignmentGuide` view modifier.

struct Example: View {
    var body: some View {
        ZStack(alignment: .twoThirdsLeading) {
            Color.cyan
            TitleView()
                .alignmentGuide(.twoThirds) { context in
                    ...
                }
            RedLine()
        }
    }
}

The `alignmentGuide` modifier is very similar to the `defaultValue` function of `AlignmentID`. In the first parameter, we specify which alignment we're modifying. In this case, it's our custom `twoThirds` alignment. Then we provide a closure which receives a `ViewDimension` describing the sizing of the `TitleView`. In this closure, we're again responsible for returning an offset in the view's coordinate space. Instead of returning two-thirds of the view's height, we'll now return half of the view's height.

struct Example: View {
    var body: some View {
        ZStack(alignment: .twoThirdsLeading) {
            Color.cyan
            TitleView()
                .alignmentGuide(.twoThirds) { context in
                    context.height / 2
                }
            RedLine()
        }
    }
}

A cyan ZStack with a "Hello, SwiftUI!" text label aligned to the leading edge and vertically centered at two-thirds the height of the container. A horizontal red line crosses the ZStack at two-thirds of its height.

Text Vertically Centered at Two-Thirds

And we're done! The `TitleView` is now vertically centered at two-thirds of the height of its container. Try experimenting with different combinations of standard alignments, custom alignments, and `alignmentGuide` to see what layouts you can come up with.

Thanks for reading!

_Paul works at_ [_Livefront_](https://livefront.com/) _, where the test coverage is strong, the designs are good looking, and all the developers are above average._

-   Paul Himes

    Software Engineer

    [More from Paul](/team/paul-himes/)

    Paul Himes

### Tags

[Digital Engineering](/insights/all/?topic=digital-engineering) [Mobile Apps](/insights/all/?topic=mobile-apps)

### Share

-   Copied

## View these next.

[See all](/insights/all/?type=writing)

-   [

    Article

    How To Sabotage Your Project Using Inconsistency

    Collin Flynn

    ](/writing/how-to-sabotage-your-project-using-inconsistency/)
-   [

    Article

    Unit Testing race conditions by creating chaos (Swift)

    Sean Berry

    ](/writing/unit-testing-race-conditions-by-creating-chaos-swift/)
-   [

    Article

    UIApplicationDelegate call sequence reference

    Sean Berry

    ](/writing/uiapplicationdelegate-call-sequence-reference/)
