44

With a simple List in SwiftUI, how do I change/remove the standard background color for the section header

struct ContentView : View {
    var body: some View {
        List {
            ForEach(0..<4) { section in
                Section(header: Text("Section")) {
                    ForEach(0..<4) { row in
                        Text("Row")
                    }
                }
            }
        }
    }
}

Screenshot with grey section header background

12 Answers 12

76

No need to change appearance of all lists or do anything strange, just:

  1. (Optional) Put .listStyle(GroupedListStyle()) on your List if you do not want sticky headers.
  2. Set the listRowInsets on the section to 0.
  3. Set the Section.backgroundColor to clear to remove the default color, or whatever color you want to color it.

Example:

List {
    Section(header: HStack {
        Text("Header")
            .font(.headline)
            .foregroundColor(.white)
            .padding()

            Spacer()
    }
    .background(Color.blue)
    .listRowInsets(EdgeInsets(
        top: 0,
        leading: 0,
        bottom: 0,
        trailing: 0))
    ) {
        // your list items
    }
}.listStyle(GroupedListStyle()) // Leave off for sticky headers

Example List with Section Header Colored

Sign up to request clarification or add additional context in comments.

10 Comments

This did not work. All it did for me was push the title (eg, "Header") to the edges and make a thin blue band behind the text. The section header's gray was still present.
At first this did not work until I realized I had left .listStyle(GroupedListStyle()) on the List. Once I removed that, this solution also worked.
But I do not want GroupedListStyle() I want sticky headers
I got good results with this, but had to not use Step 1, and I notice the example above itself does not set GroupedListStyle.
Currently this solution doesn't work in landscape on iOS 14.2. It doesn't respect the safe on both sides.
|
19

The suggested solutions works until you decide to clear your List header background color.

Better solutions for List header custom color:

1.This solution effects all of the List sections in your app: (or move it to your AppDelegate class)

struct ContentView: View {

init() {
      UITableViewHeaderFooterView.appearance().tintColor = UIColor.clear
    }

var body: some View {
    List {
        ForEach(0 ..< 3) { section in
            Section(header:
                    Text("Section")
            ) {
                ForEach(0 ..< 3) { row in
                    Text("Row")
                }
            }
        }
     }
  }
}

2.With this solution you can have custom List header background color for each list in your app:

struct ContentView: View {
init() {
    UITableViewHeaderFooterView.appearance().tintColor = UIColor.clear
}

var body: some View {
    List {
        ForEach(0 ..< 3) { section in
            Section(header:
                HStack {
                    Text("Section")
                    Spacer()
                }
                .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
                .background(Color.blue)

            ) {
                ForEach(0 ..< 3) { row in
                    Text("Row")
                }
            }
        }
     }
  }
}

4 Comments

@user832 Im using it in iOS 14.2 and it works
Thanks for letting me know. I was using NavigationLink in my section header and it was causing problem. I tried again with some changes and it worked.
For clear background this one worked for me, 'UITableViewHeaderFooterView.appearance().backgroundView = UIView()'
@FRIDDAY this no longer works for iOS 16
13

In beta 4, relativeWidth was deprecated. Code updated to reflect that.

Unfortunately, there's no quick parameter to set the background color. However, you can still do it:

enter image description here

import SwiftUI

struct ContentView : View {
    var body: some View {
        List {
            ForEach(0...3) { section in
                Section(header:
                            CustomHeader(
                                name: "Section Name",
                                color: Color.yellow
                            )
                        ) {
                    ForEach(0...3) { row in
                        Text("Row")
                    }
                }
            }
        }
    }
}

struct CustomHeader: View {
    let name: String
    let color: Color

    var body: some View {
        VStack {
            Spacer()
            HStack {
                Text(name)
                Spacer()
            }
            Spacer()
        }
        .padding(0).background(FillAll(color: color))
    }
}

struct FillAll: View {
    let color: Color
    
    var body: some View {
        GeometryReader { proxy in
            self.color.frame(width: proxy.size.width * 1.3).fixedSize()
        }
    }
}

8 Comments

Doesn't work really well when rotating the device, though.
iPhone XR. But setting a larger relativeWidth fixes it.
Oops. I see it. Updated the code with a larger relative width.
@AndreCarrera The answer was posted back when relativeWidth was a valid option. Code updated.
Currently this solution doesn't fully work in landscape on iOS 14.2. It doesn't respect the safe area on the left side.
|
8

I tried to use the custom header code above, and unfortunately could not get it to work in beta 6. That led me to the use of a ViewModifier:

public struct sectionHeader: ViewModifier{
var backgroundColor:Color
var foregroundColor:Color
public func body(content: Content) -> some View {
    content
    .padding(20)
    .frame(width: UIScreen.main.bounds.width, height: 28,alignment:
    .leading)
    .background(backgroundColor)
    .foregroundColor(foregroundColor)
}}

Which can be added to the sections in your list as follows:

struct ContentView: View {
@ObservedObject var service = someService()
var body: some View {
    NavigationView {
        List{
            ForEach(someService.sections) {section in
                Section(header: Text(section.title).modifier(sectionHeader(backgroundColor: Color(.systemBlue), foregroundColor: Color(.white)))){

Hope that helps somebody!

3 Comments

Just make sure you do not add .listStyle() modifier to the list as that will impose its own view on the section headers.
This works on startup, but gets broken on rotation, as the width is not updated properly. Also it doesn't respect the proper safe area size in landscape.
Thanks. this is the only solution that works for me.
8

You have to use a rectangle combined with .listRowInsets on the view for your header section

Section(header: headerSectionView) {
    Text("MySection")
}


private var headerSectionView: some View {
    Rectangle()
        .fill(Color.blue) // will make a blue header background
        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
        .overlay(
            Text("My Section Title")
                .padding(.horizontal), // You need this to add back the padding
            alignment: .leading
        )
}

3 Comments

this is the only solution that worked for me
It works, but if I increase the font size there is basically no top and bottom padding. How do I increase that?
You could try making the rectangle the background of the text instead of making the text an overlay. Its been a while since I answered this. I think iOS 14+ has some APIs to do this without the hacks.
7

I was able to get the header to be clear (become white in my case) by using the custom modifiers. I needed to use listStyle() modifiers and all of the above didn't work for me.

Hope it helps someone else!

List {
    Section(header: HStack {
        Text("Header Text")
            .font(.headline)
            .padding()

            Spacer()
    }
    ) {
ForEach(0...3) { row in
                        Text("Row")
                    }
    }
}.listStyle(GroupedListStyle()).listSeparatorStyle()

public struct ListSeparatorStyleModifier: ViewModifier {
    public func body(content: Content) -> some View {
        content.onAppear {
            UITableView.appearance().separatorStyle = .singleLine
            UITableView.appearance().separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            UITableViewHeaderFooterView.appearance().tintColor = .clear
            UITableView.appearance().backgroundColor = .clear // tableview background
            UITableViewCell.appearance().backgroundColor = .clear

        }
    }
}

extension View {
    public func listSeparatorStyle() -> some View {
        modifier(ListSeparatorStyleModifier())
    }
}

3 Comments

Without GroupedListStyle this has no effect on iOS 14.2. The section background color stays the default gray. It seems that UITableViewHeaderFooterView is not a part of the picture anymore.
Perfect. worked like charm.. Keep on answering Bro
Without GroupedListStyle this has no effect
4

Since iOS 16 you could use the scrollContentBackground(_:) modifier.

Reference here

In your example:

struct ContentView : View {
    var body: some View {
        List {
            ForEach(0...3) { section in
                Section(header: Text("Section")) {
                    ForEach(0...3) { row in
                        Text("Row")
                    }
                }
            }
        }
        .scrollContentBackground(.hidden)
    }
}

Comments

4

For future readers, the correct way is to use listRowBackground in the same manner as it is used for rows, but applied to sections.

Doing this way is also possible to use clear color.

Here is the code:

struct ContentView: View {
    var body: some View {
        List {
            ForEach(0..<4) { section in
                Section {
                    Text("Section #\(section)")
                }
                .listRowBackground(Color.yellow)

                ForEach(0..<4) { row in
                    Text("Item #\(row)")
                }
            }
            .listRowBackground(Color.red)
        }
        .listStyle(.plain)
    }
}

Output:

enter image description here

1 Comment

Also removes sticky headers in the process! nice!
3

I found a better solution

UITableViewHeaderFooterView.appearance().backgroundView = .init()

1 Comment

The problem with this is that it could break at any time if apple changes the behaviour of SwiftUI lists. It probably doesn't work anymore in iOS 16 as Lists are no longer backed by UITableView. They now use UICollectionView. So you probably have to use the equivalent appearance API for collection views.
2

iOS 16.4

Removing/Changing section header BG color

Use .listStyle(.plain) modifier to replace sections' header default BG color with a .clear color. To change sections' header color, use the same modifier and add a desired BG color in ZStack.

struct ContentView : View {
    var body: some View {
        ZStack {
            // Color.yellow.opacity(0.1).ignoresSafeArea()
            List {
                ForEach(0..<4) { section in
                    Section(header: Text("Section").font(.title)) {
                        ForEach(0..<4) { row in
                            Text("Row")
                        }
                    }
                }
            }.listStyle(.plain)            // clear color
        }
    }
}

enter image description here

1 Comment

This will keep a translucent background after scroll
1

Another way you can do it by setting the frame of the header:

        VStack {
            List {
                ForEach(0...3) { section in
                    Section(header:
                        Text("Section")
                            .frame(minWidth: 0, maxWidth: .infinity,alignment:.leading)
                            .background(Color.blue.relativeWidth(2))
                    ) {
                        ForEach(0...3) { row in
                            Text("Row")
                        }
                    }
                }
            }
        }

3 Comments

I had to do this to the above to get it to work. Section(header: Text("Group").frame(minWidth: 0, maxWidth: .infinity,alignment: .leading).background(Color.gray))
When I did this it mostly worked nicely, however the coloured section header bar does not reach to the sides of the display, so I'm left with a small grey section at each end which is rather disappointing. Do you know how to resolve this?
relativeWidth does not exist on iOS 14.2
0

iOS 16.0 or later

Removing/Changing section header Background

Works properly with safe area and orientation changes.

Use .scrollContentBackground(.hidden) and then set whatever background you want using .background(_:alignment:).

Example:

struct ContentView : View {
    var body: some View {
        List {
            ForEach(0..<4) { section in
                Section(header: Text("Section")) {
                    ForEach(0..<4) { row in
                        Text("Row")
                    }
                }
            }
        }
        .listStyle(.plain)
        .scrollContentBackground(.hidden)
        .background(Color.yellow.ignoresSafeArea())
    }
}

Output

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.