Introduction
SwiftUI is Apple’s modern framework for building user interfaces across all its platforms: iOS, iPadOS, macOS, watchOS, and tvOS. Introduced in 2019, SwiftUI proposes a declarative approach, where developers describe whatthey want to display on screen instead of how to draw it step by step.
One of the most fundamental elements when presenting information in any application is a list of data: contact lists, task managers, message inboxes, product catalogs, settings screens, and more. In UIKit, this role was mainly fulfilled by UITableView. In SwiftUI, the equivalent component is List.
This article explains in depth:
- What
Listis in SwiftUI - How it works conceptually
- How to use
Listin Xcode to present data - How to work with static and dynamic data
- How to customize rows, styles, and interactions
- Best practices and common mistakes
By the end, you will have a solid understanding of List and be able to use it confidently in your projects.
What Is List in SwiftUI?
List is a SwiftUI view designed to display collections of data as vertically scrolling rows. Each element in the collection is represented as a row.
Conceptually, List:
- Is scrollable by default
- Automatically manages view reuse
- Adapts to the platform’s native style (iOS, macOS, etc.)
- Supports selection, editing, deletion, and reordering
- Works reactively with SwiftUI’s state system
In other words, List is the standard and recommended way to display structured data in SwiftUI.
List vs ScrollView + VStack
Before diving into code, it’s important to address a common question:
Why use List instead of a ScrollView with a VStack?
Key differences
List:
- Optimized for large amounts of data
- Efficiently loads and unloads rows
- Native support for editing (swipe actions, delete, reorder)
- Automatically follows system styling
ScrollView + VStack:
- More visual control
- Not optimized for thousands of items
- No built-in editing support
- Better suited for custom layouts
Practical rule:
Use List when displaying data. Use ScrollView when building layouts.
Creating Your First List in SwiftUI
Let’s start with the simplest case: a list with static data.
Basic example
struct ContentView: View {
var body: some View {
List {
Text("Apple")
Text("Banana")
Text("Orange")
}
}
}This code creates a list with three rows. Each Text view automatically becomes a row in the list.
When you run this project in Xcode, you will see:
- A white (or system-colored) background
- Row separators
- Automatic scrolling if the list grows
List with Dynamic Data
The real power of List appears when working with collections of data.
Using a simple array
struct ContentView: View {
let fruits = ["Apple", "Banana", "Orange"]
var body: some View {
List(fruits, id: \.self) { fruit in
Text(fruit)
}
}
}Several important things are happening here:
Listreceives a collection (fruits)- The
id: \.selfparameter tells SwiftUI how to identify each element - SwiftUI requires a unique identifier for each row
The Identifiable Protocol
When working with more complex data models, it is strongly recommended to use Identifiable.
Model example
struct Fruit: Identifiable {
let id = UUID()
let name: String
let color: String
}Using it in a List
struct ContentView: View {
let fruits = [
Fruit(name: "Apple", color: "Red"),
Fruit(name: "Banana", color: "Yellow"),
Fruit(name: "Orange", color: "Orange")
]
var body: some View {
List(fruits) { fruit in
Text(fruit.name)
}
}
}hanks to Identifiable, there is no need to manually provide an id.
Customizing Rows
A row in a List does not have to be just a Text view. It can be any SwiftUI view.
Row with HStack
List(fruits) { fruit in
HStack {
Circle()
.fill(Color.red)
.frame(width: 12, height: 12)
Text(fruit.name)
.font(.headline)
Spacer()
Text(fruit.color)
.foregroundColor(.secondary)
}
}This allows you to build rich, professional-looking rows similar to those found in real-world apps.
Separators and List Styles
SwiftUI automatically adapts the list’s appearance, but you can customize it.
Changing the list style
List(fruits) { fruit in
Text(fruit.name)
}
.listStyle(.plain)Other common styles include:
.inset.insetGrouped.grouped.sidebar(macOS / iPad)
Choosing the correct style depends on the type of app you are building.
Sections in List
Sections allow you to group related data, which is very common in settings screens or catalogs.
Example with sections
List {
Section(header: Text("Fruits")) {
Text("Apple")
Text("Banana")
}
Section(header: Text("Vegetables")) {
Text("Carrot")
Text("Lettuce")
}
}You can also use sections with dynamic data:
List {
Section(header: Text("Fruits")) {
ForEach(fruits) { fruit in
Text(fruit.name)
}
}
}Interactions: Deleting Rows
One of the biggest advantages of List is its native editing support.
Deleting items
@State private var fruits = ["Apple", "Banana", "Orange"]
var body: some View {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
}
.onDelete { indexSet in
fruits.remove(atOffsets: indexSet)
}
}
}With this code, the user can swipe a row to delete it.
Reordering Rows
Allowing users to reorder items is just as simple.
.onMove { indices, newOffset in
fruits.move(fromOffsets: indices, toOffset: newOffset)
}To enable editing mode:
.navigationBarItems(trailing: EditButton())Navigation with List and NavigationStack
List integrates seamlessly with SwiftUI navigation.
Navigation example
NavigationStack {
List(fruits) { fruit in
NavigationLink(fruit.name) {
Text("Details for \(fruit.name)")
}
}
.navigationTitle("Fruits")
}This pattern is extremely common in iOS applications.
List and State (@State, @Binding, @ObservedObject)
List works reactively:
- When the data changes → the list updates
- No manual reloads are required
Example using @State:
@State private var fruits = ["Apple", "Banana"]
Button("Add") {
fruits.append("New fruit")
}The new row appears automatically.
Best Practices When Using List
- Use
Identifiablewhenever possible - Avoid complex logic inside rows
- Extract rows into subviews for better readability
- Avoid heavy
onAppearlogic in large lists - Choose the appropriate list style for the platform
Common Mistakes
- Using
Listfor complex layouts (useScrollViewinstead) - Not providing unique identifiers
- Mutating data without
@Stateor@ObservableObject - Overloading rows with too many views
Conclusion
List is one of the core building blocks of SwiftUI. It represents the standard, efficient, and elegant way to display structured data in Apple applications. Thanks to its declarative nature, tight integration with the state system, and built-in support for editing and navigation, List allows developers to build powerful interfaces with minimal code.
Mastering List is a fundamental step for any SwiftUI developer. Once you understand how it works, you can focus on what truly matters: the data and the user experience, while SwiftUI takes care of the rest.
If you have any questions about this article, please contact me and I will be happy to help you 🙂. You can contact me on my X profile or on my Instagram profile.