
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)
}
}
}
- Create an instance of
ScrollView
. - Depending on the needs, use a container view.
- 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)
}
}
}
}
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()
}
}
}
}
}
- Create an instance of
ScrollView
. - Use a container view and specify the
pinnedViews
parameter using the built-inPinnedScrollableViews
valuessectionHeaders
- to pin the header - andsectionFooters
- to pin the footer. - 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:)
. - Insert the content.
Pinned Header and Footer
Finally, to control the appearance of the scroll indicators, use the showsIndicators
parameter on ScrollView
, a Bool
parameter 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.
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.