Let me try out the reorderable container API in iOS 27

Let me try out the reorderable container API in iOS 27

I tried out the newly added `reorderable()` and `reorderContainer()` APIs in iOS 27. Here I summarize the results of implementing reordering functionality across multiple containers including VStack, List, and LazyVGrid.
2026.09.06

This page has been translated by machine translation. View original

Introduction

https://developer.apple.com/swiftui/whats-new/

Let's actually try out the new APIs reorderable() / reorderContainer() added in iOS 27

Now that an official API for implementing reordering has been released, reordering has become much easier to implement

Based on the session, it seems this can be applied not just to List but to various containers, which should increase UI flexibility

It also appears to work on watchOS and other platforms

Testing Environment

  • Xcode 27 beta 6
  • iOS 27.0 Simulator

※ This is verification using a beta version. Specifications may change before the official release.

First, let's read the documentation and write some code

import SwiftUI
import OrderedCollections

@main struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

// Sample data
struct Landmark: Identifiable {
    let id = UUID()
    let name: String
}

struct ContentView: View {
    @State private var landmarks: [Landmark] = [
        Landmark(name: "Mt. Fuji"),
        Landmark(name: "Kiyomizudera"),
        Landmark(name: "Himeji Castle"),
        Landmark(name: "Itsukushima Shrine"),
        Landmark(name: "Tokyo Tower"),
    ]

    var body: some View {
        VStack {
            ForEach(landmarks) { landmark in
                Text(landmark.name)
                    .padding()
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8))
            }
            .reorderable() //New API
        }
        .reorderContainer(for: Landmark.self) { difference in
            // Update the array
            difference.apply(to: &landmarks)
        } //New API
        .padding()
    }
}

// Array reordering
extension ReorderDifference where CollectionID == ReorderableSingleCollectionIdentifier {
    func apply(to values: inout [some Identifiable<ItemID>]) {
        var dictionary = OrderedDictionary(uniqueKeys: values.map { $0.id }, values: values)
        let destinationOffset: Int? = switch destination.position {
        case .before(let destination):
            dictionary.keys.firstIndex(of: destination)
        case .end:
            nil
        }
        dictionary.move(keys: sources, to: destinationOffset ?? values.endIndex)
        values = dictionary.values.elements
    }
}

https://developer.apple.com/videos/play/wwdc2026/269/?time=918

https://developer.apple.com/documentation/SwiftUI/View/reorderContainer(for:isEnabled:move:)

https://developer.apple.com/documentation/swiftui/reordering-items-in-lists-stacks-grids-and-custom-layouts

Implementation based on the above references

The WWDC video mentioned using swift-collections, so I tried creating a helper function that seemed appropriate, but honestly I'm not sure what the correct implementation looks like

Behavior

Screen Recording iPhone 17 Pro 2026-09-06 at 20.16.18

Looks great

Reordering works fine even with VStack!

Trying different containers

List

    var body: some View {
        List {
            ForEach(landmarks) { landmark in
                Text(landmark.name)
                    .padding()
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8))
            }
            .reorderable()
        }
        .reorderContainer(for: Landmark.self) { difference in
            // Update the array
            difference.apply(to: &landmarks)
        }
        .padding()
    }

Screen Recording iPhone 17 Pro 2026-09-06 at 20.38.52

Hard to tell from the GIF, but there's occasional stuttering when moving items. It works, but the behavior is a bit unstable

LazyVGrid

    private let columns = [GridItem(.adaptive(minimum: 100), spacing: 12)]

    var body: some View {
        LazyVGrid(columns: columns, spacing: 12) {
            ForEach(landmarks) { landmark in
                Text(landmark.name)
                    .padding()
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8))
            }
            .reorderable()
        }
        .reorderContainer(for: Landmark.self) { difference in
            difference.apply(to: &landmarks)
        }
        .padding()
    }

Screen Recording iPhone 17 Pro 2026-09-06 at 21.04.58

This one works nicely

Issues noticed while trying it out

When first implementing with VStack as shown in the official documentation, a warning appears during reordering

Adding 'UIView' as a subview of UIHostingController.view is not supported and may result in a broken view hierarchy. Add your view above UIHostingController.view in a common superview or insert it into your SwiftUI content in a UIViewRepresentable instead.

スクリーンショット 2026-09-06 21.01.43

I looked into it a bit but couldn't find any information about the cause of this warning related to reorderContainer

This warning appears in the VStack / LazyVGrid implementations above, but not in List

The warning disappears when wrapped in a ScrollView

I found that wrapping VStack / LazyVGrid in a ScrollView eliminates this warning. My guess is that List didn't show the warning because it's a scrollable View, but the details are unclear

Workaround below:

    var body: some View {
        ScrollView {
            VStack {
                ForEach(landmarks) { landmark in
                    Text(landmark.name)
                        .padding()
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8))
                }
                .reorderable()
            }
            .reorderContainer(for: Landmark.self) { difference in
                difference.apply(to: &landmarks)
            }
            .padding()
        }
    }

Summary

Pros

  • Reordering works with various containers
  • Being able to leave animation implementation to the system without implementing it yourself is incredibly convenient

Cons

  • Depending on the container, there can be a feeling of stutter when grabbing or reordering items
    • You'll understand if you try it on an actual device

Things I don't fully understand

  • Is my helper function implementation for reordering actually correct?
  • There were some slightly unstable behaviors, but since it's Beta, I'm hoping for improvements going forward
  • I still don't know what the best practices are, and there isn't much information available

Finally

There are other things I wanted to test, and I wasn't able to dig too deep into it, but if I feel like it, I'll explore further in a separate article!

Share this article