How to Customise the SwiftUI List Style and Background Color

SwiftUI lists have a predefined appearance which depends on the platform and situation. A list in the NavigationView sidebar has a SidebarListStyle. Using one of the default stylings will give your app the same look as native Apple apps. But what if you want to add your own styling to the list? 

In this blog post, I will show you how to customize the SwiftUI List style: hide separators, change separator colors, adjust the list background color, and the background color of individual cells. I will also give you examples of how to change section headers and footers.

By the end of this tutorial, you will be able to describe SwiftUI lists that don´t look unique and are super cool. If you are just getting started with List view, I suggest you check out my other blog post: SwiftUI List View: A Deep Dive into one of the most important components of SwiftUI.

⬇️ Download the project files here

Examples for PlainListStyle, GroupedListStyle, and InsetGroupedListStyle for SwiftUI List Styling
SwiftUI list has 5 default styling options for iOS: PlainListStyle, GroupedListStyle, InsetGroupedListStyle, InsetListStyle and SidebarListStyle.

Example Data Structure

In a previous post about SwiftUI List view, I used Food items, which I want to further extend here. I added a color variable that we will use to style our lists.

import SwiftUI
struct Food: Identifiable, Hashable {
    var name: String
    var icon: String
    var isFavorite: Bool
    var color: Color
    let id = UUID()

    static func goodExamples() -> [Food] {
        return [Food(name: "Apple", icon: "🍎", isFavorite: true, color: .red),
                Food(name: "Orange", icon: "🍊", isFavorite: false, color: .orange),
                Food(name: "Banana", icon: "🍌", isFavorite: false, color: .yellow)
        ]
    }

    static func unhealthyExamples() -> [Food] {
        [Food(name: "Pizza", icon: "🍕", isFavorite: false, color: .blue),
         Food(name: "Burger", icon: "🍔", isFavorite: false, color: .green)]
    }
}

Using a Custom Cell

We can write a custom cell to make it faster to write different implementations for List. The subview shows the food`s icon, name, and icon for the isFavorite property.

struct FoodRow: View {
    let food: Food

    var body: some View {
        HStack {
            Text(food.icon)
                .font(.title)
            Text(food.name)
            Spacer()
            Image(systemName: food.isFavorite ? "heart.fill" : "heart")
        }
    }
}

List Separators

When you use PlainListStyle, GroupedListStyle, or InsetListStyle, List shows separators between rows and sections. A List separator is not the same as a Divider. If you try to use a Divider view, it will be treated as a list row and additional spacing and styling are added. It is much better to customize the default List separators instead.

How do I hide line separators?

You can remove the List row separators with a new feature for iOS 15 and macOS 13 which is listRowSeparator. You can attach this view modifier to ForEach, a section, or directly to the individual list cell.

Each section also gets separators added after the section. You can hide section separators with the listSectionSeparator modifier:

struct ContentView: View {
    @State private var unhealthFoods = Food.unhealthyExamples()

    var body: some View {
        List {
            Section {
                ForEach(unhealthFoods) { food in
                    FoodRow(food: food)
                }
                .listRowSeparator(.hidden)
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
            .listSectionSeparator(.hidden)
        }
    }
}
Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

How to adjust List row separator color?

You can change the color of the List separators with the listRowSeparatorTint modifier. If it is attached to ForEach all separators inside are changed. ListRowSeparatorTint has an argument for the edge, which has options for all, top and bottom. It is also possible to change the separator color for individual rows by directly applying listRowSeparatorTint to the row. In our example, I used the food`s color property to apply different separator colors (first section in the following example).

If you add listRowSeparatorTint to a section, also the section separator gets the same tint color. If you only want to change the section separator use listSectionSeparatorTint.

SwiftUI list style example with separator tint color
struct ContentView: View {
    @State private var healthFoods = Food.goodExamples()
    @State private var unhealthFoods = Food.unhealthyExamples()
    var body: some View {
        List {
            Section {
                ForEach(healthFoods) { food in
                   FoodRow(food: food)
                        .listRowSeparatorTint(food.color)
                }
            } header: {
                Text("Healthy Foods")
            } footer: {
                Text("You should try to eat them regularly.")
            }

            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
            .listRowSeparatorTint(.green, edges: .all)

            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
                .listRowSeparatorTint(.blue, edges: .top)
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
            .listSectionSeparatorTint(.red)
        }
        .listStyle(.inset)
    }
}

List Row Size and Insets

SwiftUI sets default values for the height of the rows and section headers. But also for the list insets, which depend on the ListStyling. GroupedInsetListStyling will have more inset than PlainListStyling. You can override these behaviours with newer features that are backward compatible with iOS 13 and macOS 10.15.

How do I change the List row height?

List uses the default row height, that is passed in the environment. The environment value is called defaultMinListRowHeight. You can set your own value by overriding the environment value:

List {
   ...
}
.environment(\.defaultMinListRowHeight, 70)

Similarly, you can change the height of a section header with another environment property, which is defaultMinListHeaderHeight:

List {
    Section {
        ....
    } header: {
        Text("Good Foods")
    }
}
.environment(\.defaultMinListRowHeight, 70)
an example for changing the row height inside a SwiftUI List

How do I adjust List row insets?

We now have a listRowInsets modifier, where you can specify EdgeInsets. For rows you can change the leading and trailing insets. For sections, you can also set the top and bottom insets. If you attach listRowInsets to a section, the rows, section header, and footer are changed:

ForEach(unhealthFoods) { food in
         FoodRow(food: food)
}
.listRowInsets(EdgeInsets.init(top: 0, leading: 50, bottom: 0, trailing: 50))

If you want to remove all edge insets you can set .listRowInsets(.none).

SwiftUI list style example with list row insets
struct ContentView: View {
    @State private var unhealthFoods = Food.unhealthyExamples()
    var body: some View {
        List {
            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }

            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
            .listRowInsets(EdgeInsets.init(top: 20, leading: 50,
                                           bottom: 20, trailing: 50))
            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
                .listRowInsets(EdgeInsets.init(top: 0, leading: 40,
                                               bottom: 0, trailing: 40))
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
        }
    }
}

List Section Headers and Footers

You can add sections for Lists with different initializers. Some of them are deprecated with iOS 16.2 and macOS 13.1 like init(header:content:). Use init(content:header) instead, which is available for iOS 13.0+ and macOS 10.15+. This has the advantage that you can specify a view for the header and footer. For example, the following code creates a header with a larger font size that has a foreground color of pink.

swiftui list with section header that has a larger font size and pink foreground color
Section {
    ForEach(unhealthFoods) { food in
        FoodRow(food: food)
    }
} header: {
    Text("Unhealthy Foods")
        .font(.title)
        .bold()
        .foregroundColor(.pink)
        .textCase(.lowercase)
        .padding()
}

You can also use an HStack to add a button next to the section header text:

swiftui list with section header that has a text and button
Section {
    ForEach(unhealthFoods) { food in
        FoodRow(food: food)
    }
} header: {
    HStack {
        Text("Unhealthy Foods")
        Spacer()
        Button { } label: {
            Image(systemName: "plus.circle.fill")
        }
    }
    .foregroundColor(.blue)
} footer: {
    Text("You should try to avoid them and only eat them occasionally.")
        .font(.body)
}

For iOS 15.0+ you can also increase the header prominence, which makes the section header larger and bold. This works also with dynamic types.

SwiftUI List example: setting the header prominence to increased
Section {
    ForEach(healthFoods) { food in
       FoodRow(food: food)
    }
} header: {
    Text("Healthy Foods")
} footer: {
    Text("You should try to eat them regularly.")
}
.headerProminence(.increased) 

Changing the SwiftUI List Background Color

One of the most requested adjustments for the List has been to change the background of the List and the individual cells. With SwiftUI 4 the implementation of List changes. Before it was based on UITableView and now it uses UICollectionView. If you are used to some hacky solutions with UITableView.appearance(), you are in for an awesome improvement.

How to set SwiftUI List background to clear?

With iOS 16+ and macOS 13+, you can now directly remove the list background with a new modifier scrollContentBackground. This also works for ScrollView and TextEditor.

List {
    ...
}
.scrollContentBackground(.hidden)
Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

How do I modify the background color of a List in SwiftUI?

You can use scrollContentBackground to hide the default List background and then add your own:

An example of how to modify the background color of a List in SwiftUI?
struct ContentView: View {
    @State private var healthFoods = Food.goodExamples()
    @State private var unhealthFoods = Food.unhealthyExamples()

    var body: some View {
        List {
            Section {
                ForEach(healthFoods) { food in
                   FoodRow(food: food)
                }
            } header: {
                Text("Healthy Foods")
            } footer: {
                Text("You should try to eat them regularly.")
            }

            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
            } header: {
                Text("Unhealthy Foods")
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
            }
            .foregroundColor(.black)
        }
        .scrollContentBackground(.hidden)
        .background(Color.mint.edgesIgnoringSafeArea(.all))
    }
}

Adjust Cell Background inside a List

You can use the listRowBackground modifier to change the list row background. It takes a view as an argument, so you can set a color or a shape. You can add listRowBackground to Section, ForEach, or each individual row:

An example of how to change the list row background color in a SwiftUI List
List {
    Section {
        ForEach(healthFoods) { food in
           FoodRow(food: food)
                .listRowBackground(food.color)
        }
    } header: {
        Text("Healthy Foods")
    } footer: {
        Text("You should try to eat them regularly.")
    }

    Section {
        ForEach(unhealthFoods) { food in
            FoodRow(food: food)
        }
        .listRowBackground(
            Capsule()
                .fill(Color.gray)
                .padding(2)
        )
    } header: {
        Text("Unhealthy Foods")
    } footer: {
        Text("You should try to avoid them and only eat them occasionally.")
    }

    Section {
        ForEach(unhealthFoods) { food in
            FoodRow(food: food)
        }
    } header: {
        Text("Unhealthy Foods")
    } footer: {
        Text("You should try to avoid them and only eat them occasionally.")
    }
    .listRowBackground(Color.blue)
}

An Extravagant Example for SwiftUI List Style

In order to see for myself, how much we can do to achieve a unique appearance for SwiftUI list. I went and applied pretty much all available tools to a simple-looking list. Can you believe how much we now can do with SwiftUI List? – Just amazing 🙂

struct ContentView: View {

    @State private var healthyFoods = Food.goodExamples()
    @State private var unhealthFoods = Food.unhealthyExamples()

    var body: some View {
        List {
            Section {
                ForEach(healthyFoods) { food in
                   FoodRow(food: food)
                        .listRowBackground(food.color)
                }
            } header: {
                Text("Healthy Foods")
            }
            .listRowBackground(Color.blue)
            .foregroundColor(.black)

            Section {
                ForEach(healthyFoods) { food in
                    FoodRow(food: food)
                }
                .listRowBackground(
                    Capsule()
                        .fill(Color(white: 1, opacity: 0.8))
                        .padding(.vertical, 2).padding(.horizontal, 20)
                )
                .listRowSeparator(.hidden)
                .foregroundColor(.indigo)
            } header: {
                Text("Healthy Foods")
                    .font(.title)
                    .bold()
                    .foregroundColor(.white)
                    .shadow(radius: 5)
            }
            .listRowInsets(.init(top: 0, leading: 40, bottom: 0, trailing: 40))

            Section {
                ForEach(unhealthFoods) { food in
                   FoodRow(food: food)
                }
                .foregroundColor(.pink)
                .listRowInsets(.init(top: 0, leading: 60, bottom: 0, trailing: 60))
                .listRowSeparatorTint(.orange)
            } header: {
                Text("Unhealthy Foods")
                    .foregroundColor(.black)
            } footer: {
                Text("You should try to avoid them and only eat them occasionally.")
                    .foregroundColor(.white)
            }
            .listRowBackground(Color.black)
            .listSectionSeparatorTint(.yellow)
            .headerProminence(.increased)
        }
        .scrollContentBackground(.hidden)
        .background(
            Image("candies")
                .resizable()
                .scaledToFill()
                .clipped()
                .edgesIgnoringSafeArea(.all)
                .blur(radius: 3)
                .overlay(Color.indigo.opacity(0.2))
        )
        .environment(\.defaultMinListHeaderHeight, 45)
        .environment(\.defaultMinListRowHeight, 50)
    }
}

Conclusion

SwiftUI 4 brings many great improvements to the List view. You can now adjust the minimum height of a row, edge insets, section headers, and footers with ease. You also have more control over colors and backgrounds than ever before. With this tutorial, you should be able to create beautiful lists with SwiftUI. Happy coding!

Download the project files from here ⬇️

4 thoughts on “How to Customise the SwiftUI List Style and Background Color”

  1. Thank you for the post – is there a way to force a certain size (practically, height as a function of width) for a specific section row? Example: Displaying a view (an image for example, scaled in proportion, in one section row); .frame modifier doesn’t seem to do anything.

    Reply

Leave a Comment

Subscribe to My Newsletter

Want the latest iOS development trends and insights delivered to your inbox? Subscribe to our newsletter now!

Newsletter Form