Enable horizontal and vertical scrolling with ScrollView

Enable horizontal and vertical scrolling with ScrollView

Learn how to make content that exceeds the screen size scrollable using the ScrollView.

In the Apple ecosystem, there is one fundamental component users interact with through gestures that is responsible for what is displayed on the screen, the ScrollView.

When content is placed inside a container such as HStack or VStack , it can expand beyond its bounds. This is when a scrollable view is needed:  ScrollView tells SwiftUI what portion of the content should be visible, enabling scrolling as needed.

// 1.
ScrollView {
    // 2. 
    VStack {
        // 3.
        ForEach(0..<50) { number in
            Rectangle()
                .fill(colors.randomElement() ?? .gray)
                .frame(width: 350, height: 70)
        }
    }
}
  1. Create an instance of ScrollView .
  2. Depending on the needs, use a container view.
  3. Insert the content.

The interaction and the adjustment of the content on the display are gesture-based and the scroll direction can be horizontal, vertical, or both. To set the scroll direction, all that is needed is to use its standard constructor, init(_:content:), and pass the Axis.Set

ScrollView(.horizontal) {
    HStack {
        ...
    }
}

To enable both directions provide an array of Axis.Set .

ScrollView([.horizontal, .vertical]) {
    Grid {
        ForEach(0..<50) { x in
            HStack {
                Rectangle()
                    .fill(colors.randomElement() ?? .gray)
                    .frame(width: 450, height: 70)
                Rectangle()
                    .fill(colors.randomElement() ?? .gray)
                    .frame(width: 450, height: 70)
            }
        }
    }
}
0:00
/0:09

Horizontal, vertical and both directions scrolling

To manage performance when displaying long lists of content in a ScrollView, it's best to use lazy stack views like LazyVStack or LazyHStack. These stacks create their child views only when they are about to appear onscreen, reducing memory usage and improving scrolling performance, especially with large datasets.

To structure content effectively, use Section instances to group related views. Although Section itself has no visual appearance, it can include optional headers and footers. These elements can scroll along with the content or remain fixed in place using pinning modifiers, helping maintain context as users navigate through the list.

// 1.
ScrollView {
    // 2.
    LazyVStack(spacing: 1, pinnedViews: .sectionHeaders) {
        
        ForEach(0..<10) { x in
            // 3.
            Section(header:
                Text("Section \(x + 1)")
                    .bold()
            ) {
                // 4.
                ForEach(0..<10) { x in
                    Rectangle()
                        .fill(colors.randomElement() ?? .gray)
                        .frame(width: 350, height: 70)
                        .padding()
                }
            }
            
        }
    }
}
  1. Create an instance of ScrollView .
  2. Use a container view and specify the pinnedViews parameter using the built-in PinnedScrollableViews values sectionHeaders - to pin the header - and sectionFooters - to pin the footer.
  3. Use the Section using the related relevant constructor based on whether you are creating an header for the section - init(content:header:) - or a footer - init(content:footer:) .
  4. Insert the content.
0:00
/0:10

Pinned Header and Footer

Finally, to control the appearance of the scroll indicators, use the showsIndicators parameter on ScrollView , a Boolparameter set on true by default.

ScrollView([.horizontal, .vertical], showsIndicators: false) {
    ...    
}

Or achieve the same result by calling the scrollIndicators(_:axes:) method on the ScrollView and set it on hidden .

ScrollView {
    ...    
}
.scrollIndicators(.hidden)

This lets you decide whether the scroll bars should not be visible, depending on your design needs.

0:00
/0:11

Visible Indicators - Hidden Indicators


As you can see, using ScrollView in SwiftUI gives you the flexibility to present content that exceeds the screen bounds while keeping interactions natural and gesture-driven.

The combination with lazy stacks, Section, and showsIndicators control helps you build smooth, performant, and well-organized user interfaces that scale with your app’s content.