Logo for tanaschita.com

Adapting SwiftUI layouts for large Dynamic Type sizes

Learn how to restructure SwiftUI layouts when larger accessibility text sizes leave too little room for content.

05 Oct 2026 · 5 min read

A layout that works well at the default text size can become cramped when Dynamic Type increases the content size. Supporting Dynamic Type therefore also means allowing the layout to grow or change its structure.

In this article, we'll adapt a task row that works horizontally at standard text sizes but becomes difficult to read at larger accessibility sizes. For an introduction to scaling system and custom fonts, check out the article on supporting Dynamic Type in SwiftUI.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

Starting with a horizontal layout

Suppose a task row displays its title next to a due date:

HStack(alignment: .firstTextBaseline, spacing: 12) {
Text(title)
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
Label(dueDate, systemImage: "calendar")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding()
.background(.quaternary, in: .rect(cornerRadius: 12))

At a standard text size, both pieces of information have enough horizontal space. At an accessibility size, the title and due date grow while still sharing the same row. The title may wrap into a narrow column even though it would remain easy to read if it could use the full width.

To solve this, we can place the due date below the title when an accessibility size is active.

Switching layout for accessibility sizes

SwiftUI exposes the current text size through the dynamicTypeSize environment value. Its isAccessibilitySize property tells us whether the user selected one of the larger accessibility categories.

We can use that value to choose between HStackLayout and VStackLayout:

private struct TaskRow: View {
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
private var taskLayout: AnyLayout {
if dynamicTypeSize.isAccessibilitySize {
AnyLayout(
VStackLayout(alignment: .leading, spacing: 8)
)
} else {
AnyLayout(
HStackLayout(alignment: .firstTextBaseline, spacing: 12)
)
}
}
var body: some View {
taskLayout {
Text(title)
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
Label(dueDate, systemImage: "calendar")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding()
}
}

AnyLayout lets both layouts contain the same views. At standard sizes, the title and date remain next to each other. At accessibility sizes, the vertical layout gives each of them the full row width.

How AnyLayout works

Although AnyLayout is a type-erased layout, it doesn't erase the child views in the way that AnyView erases a view. It only hides whether the active layout algorithm comes from HStackLayout, VStackLayout or another type conforming to the Layout protocol.

The trailing closure still builds the Text and Label as the same child views. A type conforming to Layout receives a LayoutSubviews collection containing a proxy for each child, which it can measure and position. AnyLayout forwards those proxies to the wrapped layout algorithm. When the selected layout changes, SwiftUI therefore rearranges the existing children instead of replacing their view hierarchy, preserving their identity and state.

Choosing when to change the layout

A narrow device, a long localized title or additional row content might require the vertical layout at an earlier text size.

If the decision is primarily about the available width rather than the selected text size, ViewThatFits may be a better choice because it selects a layout based on which version fits. The article on building adaptive layouts with ViewThatFits covers that approach in more detail.

Testing at larger text sizes

We can preview the same row at different Dynamic Type sizes by changing the environment:

#Preview("Default text size") {
TaskRow(
title: "Prepare the accessibility audit article",
dueDate: "Today"
)
.padding()
}
#Preview("Accessibility 3") {
TaskRow(
title: "Prepare the accessibility audit article",
dueDate: "Today"
)
.padding()
.environment(\.dynamicTypeSize, .accessibility3)
}

Conclusion

Supporting Dynamic Type doesn't end when text grows with the user's preferred size. The surrounding layout also needs to give that text enough room.

isAccessibilitySize and AnyLayout keep that solution compact: one environment value drives the decision, and the same child views are reused in both layouts without losing their identity or state.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

accessibility

swiftui

ios

Making custom SwiftUI controls accessible with accessibilityRepresentation

Learn how to give a custom control the accessibility behavior of a native SwiftUI control.

19 Oct 2026 · 5 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum