Swift and SwiftUI tutorials for Swift Developers

What Is List in SwiftUI and How to Use It in Xcode to Present Data

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 List is in SwiftUI
  • How it works conceptually
  • How to use List in 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:

  • List receives a collection (fruits)
  • The id: \.self parameter 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

  1. Use Identifiable whenever possible
  2. Avoid complex logic inside rows
  3. Extract rows into subviews for better readability
  4. Avoid heavy onAppear logic in large lists
  5. Choose the appropriate list style for the platform

Common Mistakes

  • Using List for complex layouts (use ScrollView instead)
  • Not providing unique identifiers
  • Mutating data without @State or @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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Article

Exploring SwiftUI Stacks: VStack, HStack, and ZStack in Xcode

Next Article

How to Request App Reviews in SwiftUI Using StoreKit 2

Related Posts