Guideline 4.0

Guideline 4.0 - Design: Dynamic Type and Large Text Not Supported

Low RiskMedium DifficultyTypical Fix: 4-8 hours0 Reports
Also known as:All text uses hardcoded point sizes and ignores Dynamic Type preferencesText scales with Dynamic Type but layouts break — text is truncated or overlapsNavigation bar and tab bar labels do not scale with text size settingsCustom controls (buttons, badges, tags) use fixed sizes that clip large textApp supports standard Dynamic Type sizes but breaks at accessibility sizes (AX1–AX5)

Our Take

Apple rejected your app because it does not respect the user's Dynamic Type preferences. When users increase their preferred text size in Settings → Accessibility → Display & Text Size, your app's text does not scale accordingly. This results in text that remains too small for users who need larger text, or layouts that break, truncate, or overlap when large text sizes are enabled. Apple expects all apps to support Dynamic Type for body text, labels, and buttons.

Resolution Guide

01

**Replace hardcoded font sizes with text styles** — In SwiftUI, use semantic font modifiers instead of `.system(size:)`:

```swift

// Before: .font(.system(size: 14))

// After:

.font(.body) // 17pt default, scales with Dynamic Type

.font(.headline) // 17pt bold, scales

.font(.caption) // 12pt, scales

```


In UIKit, use `UIFont.preferredFont(forTextStyle:)`.

02

**Use @ScaledMetric for custom sizes** — When you need a specific size that still scales:

```swift

@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = 24


Image(systemName: "star")

.frame(width: iconSize, height: iconSize)

```

03

**Enable text wrapping, not truncation** — Ensure labels can expand vertically at large sizes:

```swift

Text("Long label text")

.lineLimit(nil) // allow unlimited lines

.fixedSize(horizontal: false, vertical: true) // grow vertically

```


In UIKit, set `label.numberOfLines = 0` and `label.adjustsFontForContentSizeCategory = true`.

04

**Adapt layouts for large text** — At accessibility sizes, horizontal layouts may need to become vertical. Use `@Environment(\.dynamicTypeSize)` to switch:

```swift

@Environment(\.dynamicTypeSize) var typeSize


if typeSize.isAccessibilitySize {

VStack { labelContent; valueContent }

} else {

HStack { labelContent; Spacer(); valueContent }

}

```

05

**Ensure scroll views accommodate large text** — Wrap content in ScrollView so that screens with lots of text remain usable at the largest sizes rather than clipping at the bottom.


06

**Test at all 12 Dynamic Type sizes** — In the iOS Simulator, use the Environment Overrides panel (Debug → Environment Overrides) to test at every size from xSmall to AX5. Pay special attention to AX1–AX5 (accessibility sizes) where most breakage occurs.


07

**Use Accessibility Inspector** — Xcode's Accessibility Inspector can audit your app for Dynamic Type support issues and highlight elements that don't scale.


Example Rejection Email

From:Apple App Review Team
Subject:Guideline 4.0 - Design: Dynamic Type and Large Text Not
Your app does not sufficiently support text accessibility features. Specifically, your app does not respond to the user's preferred text size setting (Dynamic Type). When the reviewer increased the text size to the largest accessibility size, text throughout the app remained at a fixed size and did not scale. Additionally, in some areas where text did partially scale, it was truncated or overlapped with other elements. Next Steps: Please update your app to support Dynamic Type and ensure layouts adapt to all text sizes.

Consider Appealing

Do not appeal this rejection. Dynamic Type support is an accessibility requirement that Apple takes seriously. The fix may take a few hours but is well worth it — it benefits users with low vision and is the right thing to do. If you've already added Dynamic Type support and the reviewer missed it, provide screenshots at the largest text size in your Resolution Center reply.

Generate Appeal

Before & After

Before — Rejected

// Hardcoded sizes — no Dynamic Type support

VStack(alignment: .leading, spacing: 8) {

Text(item.title)

.font(.system(size: 16, weight: .bold))

Text(item.subtitle)

.font(.system(size: 14))

.lineLimit(1)

HStack {

Image(systemName: "star")

.frame(width: 16, height: 16)

Text(item.rating)

.font(.system(size: 12))

}

}

After — Approved

// Dynamic Type with adaptive layout

@ScaledMetric(relativeTo: .caption) private var starSize: CGFloat = 16


VStack(alignment: .leading, spacing: 8) {

Text(item.title)

.font(.headline)

Text(item.subtitle)

.font(.subheadline)

.lineLimit(nil)

.fixedSize(horizontal: false, vertical: true)

HStack {

Image(systemName: "star")

.frame(width: starSize, height: starSize)

Text(item.rating)

.font(.caption)

}

}

What changed: Replace .system(size:) with semantic text styles (.headline, .subheadline, .caption) that scale automatically with Dynamic Type. Use @ScaledMetric for icon sizes so they grow proportionally. Remove lineLimit(1) to allow text to wrap at large sizes.

Before — Rejected

// Fixed horizontal layout that breaks at large text

HStack {

Text("Balance:")

.font(.system(size: 14))

Spacer()

Text("$1,234.56")

.font(.system(size: 14, weight: .bold))

}

After — Approved

// Adaptive layout that stacks vertically at accessibility sizes

@Environment(\.dynamicTypeSize) var typeSize


Group {

if typeSize.isAccessibilitySize {

VStack(alignment: .leading, spacing: 4) {

Text("Balance:")

.font(.subheadline)

Text("$1,234.56")

.font(.headline)

}

} else {

HStack {

Text("Balance:")

.font(.subheadline)

Spacer()

Text("$1,234.56")

.font(.headline)

}

}

}

What changed: At accessibility text sizes, horizontal space is too limited for side-by-side labels. Use @Environment(\.dynamicTypeSize) to detect large sizes and switch to a vertical layout, preventing truncation and overlap.

Community Solutions · 0

Sign in to share your solution.

More Guideline 4 (Design) rejections

View all Guideline 4 rejections