Clipped Large Text

Status: ready

Symptom

With a larger text size, text is cut off, overlaps, or pushes the primary button off screen.

Payment failed. Your ca...
Continue with...

The worst case: the Pay button is below the visible area in a view that doesn't scroll, and checkout can't be finished.

Where it shows up

Checkout, forms, settings rows, product cards, onboarding, support, compact dashboards, anything with a fixed height.

Why it blocks the task

The user chose that text size because they need it. If the app breaks at a larger size, it's telling those users to read smaller text or leave. A truncated error or a hidden button blocks the task, not just the look.

Root cause

The layout assumes the default size and short English strings.

  1. Fixed heights on rows that contain text.
  2. lineLimit(1) on text the user needs.
  3. Custom fonts that don't scale.
  4. HStack that never switches to vertical.
  5. A screen that doesn't scroll.
  6. Nobody checked German, or AX5.

Before

HStack {
    Text(product.name)
    Spacer()
    Text(product.price)
}
.frame(height: 44)

Text(error)
    .lineLimit(1)

Fix

Verdict: text styles everywhere, no fixed heights on text, a vertical layout at accessibility sizes, and every screen with a primary action scrolls.

Why: at AX5, body text is about 3 times the default size. A horizontal row with a name and a price doesn't fit in 390 pt, no matter how it's tuned.

@Environment(\.dynamicTypeSize) private var size

var body: some View {
    let layout = size.isAccessibilitySize
        ? AnyLayout(VStackLayout(alignment: .leading, spacing: 4))
        : AnyLayout(HStackLayout())

    layout {
        Text(product.name).font(.body)
        if !size.isAccessibilitySize { Spacer() }
        Text(product.price).font(.body.weight(.semibold))
    }
}

Errors wrap. No lineLimit on text the user has to read:

Text(error)
    .font(.callout)

Icons next to text scale with it:

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

Custom fonts: .font(.custom("Brand", size: 17, relativeTo: .body)). In UIKit: UIFontMetrics(forTextStyle: .body).scaledFont(for:) and adjustsFontForContentSizeCategory = true.

Preview the critical screens at AX3 and AX5:

#Preview("AX5") {
    CheckoutView().environment(\.dynamicTypeSize, .accessibility5)
}

A preview catches obvious breakage. It doesn't replace a check on a device.

Check

Profile:   Larger Text, AX5 (Settings → Accessibility → Display & Text Size → Larger Text)
Task:      complete checkout, including one validation error
Expected:  no truncated text in fields, prices, errors or buttons
           no overlap
           Pay reachable by scrolling
           the error wraps and stays next to its field
Profile:   German or Russian, AX3
Task:      the same checkout
Expected:  button verbs not truncated, price and title don't overlap

WCAG mapping

  1. 1.4.4 Resize Text: text resizes to 200% without loss of content or function.
  2. 1.4.10 Reflow: content reflows instead of requiring scrolling in two directions.

App Store and product risk

The Larger Text label in App Store Connect requires support for at least 200% text size in common tasks. Clipping is easy to show in one screenshot.

  1. Dynamic Type Contract
  1. Chapter 2
  2. Chapter 6
  3. Chapter 10
  4. Chapter 13

Sources

  1. Apple Developer: DynamicTypeSize
  2. Apple Developer: ScaledMetric
  3. Apple Developer: UIFontMetrics
  4. App Store Connect Help: Larger Text evaluation criteria
  5. Apple Human Interface Guidelines: Typography