How to Easily Create ScrollToTop in SwiftUI
Tags: swiftui, swift, ios15
Published: 2023-09-22 23:37:29

---
title: How to Easily Create ScrollToTop in SwiftUI
published: true
date: 2023-07-29 06:58:00 UTC
tags: SwiftUI,Swift,iOS15
cover_image: https://swift.my.id/content/images/2023/07/Screenshot-2023-07-29-at-14.02.16.jpg
canonical_url: https://swift.my.id/scroll-to-top-di-swiftui/
---

**Scroll to top** is an easy way for users to return to the top of a page by pressing a specific button. Typically, this page contains a long list, requiring users to scroll to view more content. When users have scrolled too far, a scroll to top button becomes essential. Without it, users would have to scroll back multiple times to return to the top.

Just like web applications and others, we can create a scroll to top button in **SwiftUI**. This button is particularly useful when you are using a **List** or **ScrollView**.

### #Widget/View ScrollViewReader

SwiftUI already provides a default widget/view that can be used for programmatic scrolling, and that is the **ScrollViewReader**.

```swift
@frozen
struct ScrollViewReader<Content> where Content : View
```

To scroll to a specific view, you need to assign an ID to that widget/view. Once the ID is defined, you can use the scrollTo method of **ScrollViewReader** to scroll to the widget/view. In general, if you want to scroll to the top of a List or **ScrollView** , you assign an ID to the topmost view.

### #ScrollToTop for List

Here is an example of how to scroll to the top of a List. For this example, we are using the simplest data, which is just numbers from 1 to 100..

```swift
struct ContentView: View {
    var body: some View {
        ScrollViewReader { proxy in
            VStack {
                List {
                    ForEach(1 ... 100, id: \.self) { i in
                        Text("Item number \(i)")
                            .id(i)
                    }
                }
                Button("Move to top") {
                    withAnimation(.easeIn(duration: 1.0)) {
                        proxy.scrollTo(1)
                    }                
                }
            }
        }
        .navigationTitle("Move to top")
    }    
}
```

In the example above, to scroll to the top, we use `scrollTo(1)`, where 1 is the ID of the first element in the List. This example is straightforward because we can be sure that the ID of the first/topmost element in the List is always 1.

The `withAnimation` here is used to provide a smoother scrolling experience with animation.

<video src="https://swift.my.id/content/media/2023/07/Screen-Recording-2023-07-29-at-13.21.09-android-phone.mp4" controls="controls">
</video>
_ScrollToTop pada List_

### #ScrollToTop for ScrollView

To perform a scroll to the top in a **ScrollView** , it's similar. Here's an example:

```swift
struct WithScrollView: View {
    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                LazyVStack {
                    ForEach(1 ... 100, id: \.self) { i in
                        Text("Item number \(i)")
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .padding(.vertical, 5)
                            .id(i)
                    }
                }
                .padding()
            }

            Button("Move to top") {
                withAnimation(.easeIn(duration: 1.0)) {
                    proxy.scrollTo(1)
                }
            }
        }
        .navigationTitle("Move to top")
    }
}
```

In the example provided, we are using a **ScrollView** with a **LazyVStack** as its content. LazyVStack is a great choice when dealing with a potentially large number of items because it only creates and loads the views that are currently visible on the screen, which can improve performance and efficiency, especially with long lists of data. This approach is commonly used when creating scrollable views with SwiftUI.

<video src="https://swift.my.id/content/media/2023/07/Screen-Recording-2023-07-29-at-13.27.36-android-phone.mp4" controls="controls">
</video>
_ScrollToTop dengan pada ScrollView_

### #ScrollToTop with Struct Data

In the previous examples, the data displayed was simple numeric arrays. This time, we will attempt to implement scroll to top with complex data, typically represented as **structs**.

For the struct data example, we will create a data struct for a `Person` with properties `id` and `name`.

```swift
struct Person: Identifiable {
    var id: Int
    var name: String

    init(id: Int, name: String) {
        self.id = id
        self.name = name
    }
}
```

With mock data as follows. The **IDs** are intentionally created randomly to illustrate that the first ID is not necessarily the smallest or zero.

```swift
    private var persons: [Person] = [
        Person(id: 11649, name: "Elmer Oconnell"),
        Person(id: 14, name: "Montgomery Norman"),
        Person(id: 8, name: "Jake Bass"),
        Person(id: 20, name: "Nikodem Garza"),
        Person(id: 31, name: "Ashwin Salinas"),
        Person(id: 79, name: "Jason Mcgowan"),
        Person(id: 1002, name: "Natasha Fernandez"),
        Person(id: 21, name: "Chris Duncan"),
        Person(id: 231, name: "Kimberly Sloan"),
        Person(id: 154, name: "Amber Mcbride"),
        Person(id: 876, name: "Chris Duncan"),
        Person(id: 5041, name: "Chantelle Dyer"),
        Person(id: 3964, name: "Alexa Lucero"),
        Person(id: 805, name: "Timothy Graves"),
    ]
```

To implement scroll to top with the above data, it is typically structured as follows.

```swift
    var body: some View {
        ScrollViewReader { proxy in
            VStack {
                List {
                    ForEach(persons) { person in
                        VStack(alignment: .leading) {
                            Text(person.name)
                            Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies ex id ex posuere blandit. Donec semper ligula ut velit molestie malesuada")
                                .font(.caption)
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                        }
                        .id(person.id)
                    }
                }
                Button("Move to top") {
                    withAnimation(.easeIn(duration: 1.0)) {
                        proxy.scrollTo(0) // ????
                    }
                }
            }
        }
    }
```

Here, a problem arises because we don't actually know the ID of the topmost element in the List. This is because `ForEach`, up to now, does not provide the index of the array, so this approach with `ForEach(persons)` can't be used.

The solution is to use the index of the persons array, which can be obtained using `.indices`. By using this index, we can scroll to the top element because its ID will always be zero.

In this code, we use `persons.indices` with the `.self` key path to loop. Through the indices of the `persons` array, allowing us to scroll to the top element by using `.id(0)` and `scrollViewProxy.scrollTo(0)`.

```swift
    var body: some View {
        ScrollViewReader { proxy in
            VStack {
                List {
                    ForEach(persons.indices, id:\.self) { i in
                        let person = persons[i]
                        VStack(alignment: .leading) {
                            Text(person.name)
                            Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies ex id ex posuere blandit. Donec semper ligula ut velit molestie malesuada")
                                .font(.caption)
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                        }
                        .id(i) // first index always 0
                    }
                }
                Button("Move to top") {
                    withAnimation(.easeIn(duration: 1.0)) {
                        proxy.scrollTo(0)
                    }
                }
            }
        }
    }
```

Here is the complete code.

```swift
struct Person: Identifiable {
    var id: Int
    var name: String

    init(id: Int, name: String) {
        self.id = id
        self.name = name
    }
}

struct WithStructData: View {
    private var persons: [Person] = [
        Person(id: 10, name: "Elmer Oconnell"),
        Person(id: 14, name: "Montgomery Norman"),
        Person(id: 8, name: "Jake Bass"),
        Person(id: 20, name: "Nikodem Garza"),
        Person(id: 31, name: "Ashwin Salinas"),
        Person(id: 79, name: "Jason Mcgowan"),
        Person(id: 1002, name: "Natasha Fernandez"),
        Person(id: 21, name: "Chris Duncan"),
        Person(id: 231, name: "Kimberly Sloan"),
        Person(id: 154, name: "Amber Mcbride"),
        Person(id: 876, name: "Chris Duncan"),
        Person(id: 5041, name: "Chantelle Dyer"),
        Person(id: 3964, name: "Alexa Lucero"),
        Person(id: 805, name: "Timothy Graves"),
    ]
    var body: some View {
        ScrollViewReader { proxy in
            VStack {
                List {
                    ForEach(persons.indices, id:\.self) { i in
                        let person = persons[i]
                        VStack(alignment: .leading) {
                            Text(person.name)
                            Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies ex id ex posuere blandit. Donec semper ligula ut velit molestie malesuada")
                                .font(.caption)
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                        }
                        .id(i)
                    }
                }
                Button("Move to top") {
                    withAnimation(.easeIn(duration: 1.0)) {
                        proxy.scrollTo(0)
                    }
                }
            }
        }
    }
}

```

<video src="https://swift.my.id/content/media/2023/07/Screen-Recording-2023-07-29-at-14.01.32-android-phone.mp4" controls="controls">
</video>
_ScrollToTop pada List dengan data Struct_

That's the tip/trick for implementing scroll to top in SwiftUI, whether with List or ScrollView. Happy experimenting, and I hope this little bit is helpful.

{% github https://github.com/meshwara/SwiftUI-ScrollToTop %}