Fix: Text Alignment in SwiftUI

Fix: Text Alignment in SwiftUI

Written by

in

Quick answer: Use .multilineTextAlignment(.center) to center lines inside a multiline Text view. To position the Text view within available space, use a frame modifier such as .frame(maxWidth: .infinity, alignment: .center); the two modifiers control different things.

Why this happens

SwiftUI separates the alignment of text inside a Text view from the position of the Text view inside its layout. That distinction is why changing a text-alignment modifier may not move a short label to the middle of the screen, or why centering a frame may not center every line of a paragraph.

A Text view normally takes the space it needs for its content. Its parent container, such as a VStack or HStack, then arranges it according to that container’s layout rules. A short Text may have no extra width in which its text could visibly shift, even if you set a text alignment.

Choose the modifier based on what you want to align: use multilineTextAlignment for the lines of text, and use frame(alignment:) to position the view in a larger area. A common result needs both: a full-width frame and centered text lines.

How to fix it

1. Center the lines inside a multiline Text

Apply multilineTextAlignment directly to the text view:

import SwiftUI

struct CenteredParagraph: View {
    var body: some View {
        Text("This paragraph wraps onto multiple lines. Center each line within the text view.")
            .multilineTextAlignment(.center)
    }
}

The modifier accepts .leading, .center, and .trailing. It changes how lines are aligned within the text view’s available width. It does not, by itself, make the view fill the screen or position it in the center of its parent.

This is the right first fix when a wrapped paragraph is left-aligned but you want each line centered. If the text is only a short, single-line label, the effect may be difficult to see because the view can be only as wide as the label.

2. Give the text room, then align it in that space

To center a label within the width offered by its parent, make its frame flexible and set the frame’s alignment:

Text("Centered")
    .frame(maxWidth: .infinity, alignment: .center)

The frame can expand into the available width, and alignment: .center positions the Text inside that frame. This is often the simplest choice for a title or label in a VStack.

You can use the same approach for leading or trailing placement:

Text("Account details")
    .frame(maxWidth: .infinity, alignment: .leading)

leading and trailing are semantic alignments. They follow the current layout direction, which is generally preferable for interface text that should adapt to right-to-left languages.

A flexible frame can only use space its parent offers. If the parent itself is narrow, the text cannot expand beyond that parent. Check the surrounding layout before assuming the frame modifier is being ignored.

3. Center both a paragraph’s lines and its view

For a paragraph that should occupy the available width with every line centered, combine the two modifiers:

Text("A longer message can wrap across several lines. Center each line and center the text view in its available area.")
    .multilineTextAlignment(.center)
    .frame(maxWidth: .infinity, alignment: .center)

Here, multilineTextAlignment controls the text’s lines. The frame modifier controls the placement of the Text view. Keeping both makes the intent clear and avoids relying on the text’s natural size to produce the layout you expect.

4. Use a fixed or constrained width when wrapping matters

If you need a paragraph to wrap at a particular width, give it a width constraint. For example:

Text("This message wraps within a readable column and centers its lines.")
    .frame(maxWidth: 320)
    .multilineTextAlignment(.center)

The maximum width limits how wide the text can become; the text then wraps as needed. If you also want the resulting column centered in a wider parent, put it in a frame that takes the available width:

Text("This message wraps within a readable column and centers its lines.")
    .frame(maxWidth: 320)
    .multilineTextAlignment(.center)
    .frame(maxWidth: .infinity, alignment: .center)

Use a fixed width only when the design calls for one. A maximum width is usually more adaptable across different device sizes.

5. Check the parent container

If the text still appears misplaced, inspect the parent’s layout. A VStack aligns its children horizontally according to its alignment parameter; an HStack arranges children horizontally and may need a Spacer or a frame to position them. For example, this pushes a label to the trailing edge of an HStack:

HStack {
    Text("Status")
    Spacer()
}

Do not use multilineTextAlignment to solve a parent-layout problem. Conversely, do not expect a frame’s alignment to change how multiple lines inside a paragraph are aligned. Decide whether the issue is the text’s lines, the text view’s position, or the arrangement of its parent, then apply the corresponding layout rule.

How to prevent it

  • Use multilineTextAlignment when you mean to align lines within text.
  • Use a frame’s alignment when you mean to position a view within extra space.
  • Remember that a short label may not have extra width unless its parent or frame provides it.
  • Prefer .leading and .trailing over .left and .right for layouts that should adapt to reading direction.
  • Check the parent container’s alignment and available size when a modifier appears to have no effect.

FAQ

Why does .multilineTextAlignment(.center) not center my label?

It aligns text lines within the Text view; it does not make that view fill its parent. Add a flexible frame, such as .frame(maxWidth: .infinity, alignment: .center), when the label needs to be centered in the available width.

What is the difference between text alignment and frame alignment?

multilineTextAlignment controls the alignment of lines inside the text. frame(alignment:) controls where the view sits inside its frame. A paragraph may need both modifiers.

Should I use .leading or .left?

Use .leading for most interface text because it follows the layout direction. .left means the physical left side, regardless of whether the interface is laid out right to left.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.