Skip to content

ScrollView Target Behavior (SwiftUI)

A SwiftUI guide for coding agents. Also covers scroll snapping ios, scrolltargetbehavior, paging scrollview, viewaligned snapping, scrolltargetlayout, custom snap behavior.

scrollTargetBehavior, new in iOS 17, controls where a ScrollView settles when the user lets go: full pages, aligned views, or a rule you write yourself.

Paging and View Alignment

.paging snaps by the container size, one page per swipe. .viewAligned decelerates until the first visible item aligns with the viewport edge.

ScrollView {
    ForEach(0..<100) { number in
        Text(verbatim: String(number))
            .frame(maxWidth: .infinity, minHeight: 300)
    }
}
.scrollTargetBehavior(.paging)

Mark the Target Layout

With a lazy container inside the scroll view, viewAligned needs to know which views are snap targets. Put scrollTargetLayout on the LazyVStack, LazyHStack, or LazyVGrid.

ScrollView(.horizontal) {
    LazyHStack {
        ForEach(0..<100) { number in
            Text(verbatim: String(number))
        }
    }
    .scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)

Only the marked container participates: a header before it and a footer after it stay ordinary content. The behavior follows whichever axes the ScrollView enables.

Custom Behaviors

Conform to ScrollTargetBehavior and implement updateTarget. Mutate the inout ScrollTarget rect to choose the landing position; the context supplies velocity, axes, container size, content size, and the original target.

struct CustomScrollTargetBehavior: ScrollTargetBehavior {
    func updateTarget(_ target: inout ScrollTarget, context: TargetContext) {
        if context.velocity.dy > 0 {
            target.rect.origin.y = context.originalTarget.rect.maxY
        } else if context.velocity.dy < 0 {
            target.rect.origin.y = context.originalTarget.rect.minY
        }
    }
}

extension ScrollTargetBehavior where Self == CustomScrollTargetBehavior {
    static var custom: CustomScrollTargetBehavior { .init() }
}

Then apply it like the built-ins: .scrollTargetBehavior(.custom).

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-mastering-scrollview-target-behavior" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems