If you’re building dynamic lists or repeating UI components in SwiftUI, there’s a high chance you’re already using the SwiftUI ForEach view element. It’s a powerful, yet sometimes misunderstood, view element in SwiftUI.
This article will help you understand how ForEach
works and when and how to use it. We’ll also dive into index-based iteration and how the Identifiable
protocol can help you out.
What is SwiftUI ForEach?

The SwiftUI ForEach view allows you to iterate over a collection and generate views for each element. It’s especially useful when working with List
, LazyVStack
, or any container that supports multiple children.
struct ContentView: View {
let names = ["Antoine", "Maaike", "Sep", "Jip"]
var body: some View {
ForEach(names, id: \.self) { name in
Text(name)
}
}
}
In the above example, we iterate over all names in the collection by using \.self
as the identifier since String
conforms to Hashable
. For custom types, it’s better to provide a unique identifier via the Identifiable
protocol.
ForEach with Identifiable Data
Iterating over a collection using the Identifiable
protocol is the cleanest approach. It allows us to remove the \.self
identifier and rely on the id
property requirement of the Identifiable
protocol instead:
struct ContentView: View {
let people = [
Person(id: UUID(), name: "Antoine"),
Person(id: UUID(), name: "Maaike")
]
var body: some View {
ForEach(people) { person in
Text(person.name)
}
}
}
Using Identifiable
helps SwiftUI track view identity across state updates and avoid unnecessary redraws.
Using ForEach in Lists
When used inside a List
, the SwiftUI ForEach view becomes essential for rendering dynamic rows:
List {
ForEach(people) { person in
HStack {
Image(systemName: "person")
Text(person.name)
}
}
}
Iterating with an Index
By using an enumerated array, you can iterate over items and their indexes:
ForEach(Array(people.enumerated()), id: \.offset) { index, person in
Text("Index \(index): \(person.name)")
}
This can occasionally be useful if you need to have the index at hand while performing index-based view styling, for example.
Conclusion
SwiftUI ForEach is an essential part of building dynamic interfaces. It’s recommended to use it in combination with the Identifiable
protocol, but using the id
parameter should work in most cases too. You can use an enumerated array if you also need to have the index for each item while iterating.
If you’re interested in learning more about other SwiftUI elements, I recommend the following articles:
- SwiftUI Alert Guide + Code Examples
- SwiftUI Grid, LazyVGrid, LazyHGrid Explained with Code Examples
- SwiftUI TabView: Explained with Code Examples
- Picker in SwiftUI explained with code examples
- SwiftUI Lists: Present rows of data explained with code examples
- SwiftUI Button: Custom Styles, Variants, and Best Practices
If you want to improve your SwiftUI knowledge, even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.
Thanks!