What's New in SwiftUI for iOS 27
Skip to content
English
English
简体中文
繁體中文
Français
Deutsch
日本語
한국어
Polski
Português
Español
English
简体中文
繁體中文
Français
Deutsch
日本語
한국어
Polski
Português
Español
What's New in SwiftUI for iOS 27
June 08, 2026<br>22 min read
swiftui
ios
ios-27
swift
apple
Every SwiftUI release tells you where the framework’s pressure points were by what Apple decided to rebuild. iOS 27’s answer is unusually broad: lists get first-class reordering, documents get a new reader/writer protocol family, toolbars get an overflow model with explicit priority, and error presentation finally gets a binding you can hand an Error directly. The release moves four surfaces at once, and most apps touch at least two of them.1
The temptation with a release this wide is to adopt everything. The better move is to recognize which additions change how you build versus which are convenience overloads on patterns you already use. Drag-to-reorder and the document protocols are the former: they replace code you wrote by hand. Item-based alerts and AsyncImage(request:) are the latter: they remove a workaround. This post sorts the iOS 27 SwiftUI surface into those threads, with the real declarations and the reasoning for when each one earns its place in your code.
TL;DR / Key Takeaways
Lists and custom containers get declarative reordering: reorderContainer(for:isEnabled:move:) marks a container, reorderable() on DynamicViewContent opts the rows in, and you receive a ReorderDifference instead of writing index-math by hand.23
Lazy drag containers arrive through dragContainer(for:itemID:in:_:) plus draggable(containerItemID:containerNamespace:), which carries only an identifier so the framework fetches payloads lazily when a drag starts.45
A new document model lands as ReadableDocument and WritableDocument (with DocumentReader/DocumentWriter doing the on-disk work and FileWrapperDocumentReader/FileWrapperDocumentWriter for the simple case), backed by URLDocumentConfiguration.6789101112
Toolbars gain ToolbarOverflowMenu, the topBarPinnedTrailing placement, and visibilityPriority(_:), so you decide which controls survive when the bar runs out of room.131415
Error presentation gets alert(error:actions:message:) and item-based alert(_:item:actions:) / confirmationDialog, plus AsyncImage(request:) for full URLRequest control and asyncImageURLSession(_:) to share a session.1617181920
Rounding out the surface: swipeActions(...onPresentationChanged:), swipeActionsContainer(), NavigationTransition.crossFade, TabRole.prominent, UIHostingSceneDelegate, and GestureInputKinds.212223242526
Drag-To-Reorder Becomes Declarative
Reordering a list in SwiftUI used to mean onMove, an index set, and a destination offset you translated into your own model mutation. iOS 27 replaces that with a two-part declaration: you mark a container as reorderable, and you mark its content as participating. The container then hands you a structured diff.
The single-collection case is the common one. You declare reorderContainer(for:isEnabled:move:) on the container and reorderable() on the DynamicViewContent inside it:23
struct LandmarkList: View {<br>@State private var landmarks: [Landmark]
var body: some View {<br>List {<br>ForEach(landmarks) { landmark in<br>LandmarkRow(landmark: landmark)<br>.reorderable()<br>.reorderContainer(for: Landmark.self) { difference in<br>// Apply the reorder to your model.<br>landmarks.apply(difference)
The signature tells you the contract. The container modifier is generic over Item : Identifiable and gives you a ReorderDifference:2
nonisolated func reorderContainerItem>(<br>for item: Item.Type,<br>isEnabled: Bool = true,<br>move: @escaping (ReorderDifferenceItem.ID, ReorderableSingleCollectionIdentifier>) -> ()<br>) -> some View where Item : Identifiable, Item.ID : Sendable
Two design decisions matter here. First, the framework drives the interaction: as Apple’s documentation describes it, a reorderable item can be lifted with a drag gesture, a placeholder view takes its position to show where the item will land, and the placeholder tracks the drag through the container.2 You no longer build that affordance; you describe the collection and react to the result. Second, isEnabled is a parameter rather than a separate modifier, so an edit-mode toggle becomes one boolean instead of conditional view construction.
When a container holds more than one collection, you reach for the overload that takes a collection identifier type, reorderContainer(for:in:isEnabled:move:):27
nonisolated func reorderContainerItem, CollectionID>(<br>for item: Item.Type,<br>in collectionID: CollectionID.Type,<br>isEnabled: Bool = true,<br>move: @escaping (ReorderDifferenceItem.ID, CollectionID>) -> ()<br>) -> some View where Item : Identifiable, CollectionID : Hashable, CollectionID : Sendable, Item.ID : Sendable
The ReorderDifference is now keyed by both the item ID and a collection ID, so a move that crosses from one section into another...