'How to remove List Separator lines in SwiftUI 2.0 in iOS 14 and above
So the question is pretty simple and it's in the title. I want to remove the line separator in SwiftUI iOS 14. Previously, I was using
UITableView().appearance().separatorStyle = .none
and that used to do the job in iOS 13. Now however, it doesn't work. Any update or idea on how to make it work. Thanks:)
Solution 1:[1]
Here is a demo of possible solution. Tested with Xcode 12b.
List {
ForEach(0..<3) { _ in
VStack {
Text("Hello, World!").padding(.leading)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.listRowInsets(EdgeInsets())
.background(Color(UIColor.systemBackground)))
}
}
Solution 2:[2]
How I made a list that works on both iOS 14 and iOS 13, It shows no separators and extra margins
struct NoButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
}
}
struct ListWithoutSepatorsAndMargins<Content: View>: View {
let content: () -> Content
var body: some View {
if #available(iOS 14.0, *) {
ScrollView {
LazyVStack(spacing: 0) {
self.content()
}
.buttonStyle(NoButtonStyle())
}
} else {
List {
self.content()
}
.listStyle(PlainListStyle())
.buttonStyle(NoButtonStyle())
}
}
}
Sample Usage -
ListWithoutSepatorsAndMargins {
ForEach(0..<5) { _ in
Text("Content")
}
}
in case you've more components in list, wrap them in Group
ListWithoutSepatorsAndMargins {
Group {
self.groupSearchResults()
self.myGroups()
self.exploreGroups()
}
}
}
Hope this helps someone, I wasted a lot of time in such minor thing, Apple is trying to push us hard to use LazyVStack, it seems
Solution 3:[3]
Merged @asperi, @akmin and @zrfrank answer into one thing. In my experience List is more reliable and efficient than LazyVStack, so I use still use List for anything complex requiring reliability.
extension View {
func listRow() -> some View {
self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.listRowInsets(EdgeInsets(top: -1, leading: -1, bottom: -1, trailing: -1))
.background(Color(.systemBackground))
}
}
List {
Color.red
.listRow()
Color.green
.listRow()
}
Solution 4:[4]
I found this simple solution on the Apple Developer forums. It's working for me on 14.4:
List {
...
}.listStyle(SidebarListStyle())
This seems to add a tiny bit of padding around the edges. If that's a problem for you, you could try some negative padding.
Solution 5:[5]
iOS 15:
This year Apple introduced a new modifier .listRowSeparator that can be used to style the separators. you can pass .hidden to hide it:
List(items, id:\.self) {
Text("Row \($0)")
.listRowSeparator(.hidden)
}
? Also you can set each separator to any color by settings listRowSeparatorTintColor as I mentioned here in this answer:

iOS 14
Follow the answer here
Solution 6:[6]
Based on average Joe's answer I ended up with the following modifier:
struct ListSeparatorNone: ViewModifier {
var backgroundColor: Color = Color(.systemBackground)
func body(content: Content) -> some View {
content
.listRowInsets(EdgeInsets(top: -1, leading: 0, bottom: 0, trailing: 0))
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(backgroundColor)
}
}
The view extension:
extension View {
func listSeparatorNone(backgroundColor: Color = Color(.systemBackground)) -> some View {
self.modifier(ListSeparatorNone(backgroundColor: backgroundColor))
}
}
Usage example:
List {
ForEach(viewModel.countries, id: \.self) { country in
Text(country)
.padding(.leading, 10)
}
.listSeparatorNone()
}
Solution 7:[7]
If you don't have a lot of cells, and therefore don't need to rely on a LazyVStack for performance, you can fallback to a ScrollView + VStack:
ScrollView {
VStack {
Row1()
Row2()
Row3()
}
}
Solution 8:[8]
You can also call this function at the end of your VStack (that is inner the List).
It will be an overlay on List Seperator on iOS 14 :)
private func hideDefaultListSeperator() -> some View {
Rectangle()
.fill(colorScheme == .light ? Color.white : Color.black)
.frame(maxHeight: 1)
}
Solution 9:[9]
Update:
I figured out a solution that works on both iOS 13 and iOS 14 and gives a simple list and uses List on both iOS.
struct ListWithoutSepatorsAndMargins<Content>: View where Content: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
List {
self.content()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.listRowInsets(EdgeInsets())
.background(Color.white)
}
.listStyle(PlainListStyle())
.buttonStyle(NoButtonStyle())
}
}
struct NoButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
}
and do the following in SceneDelegate.swift to remove default grey selection of cells
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
UITableView.appearance().separatorStyle = .none
UITableView.appearance().allowsSelection = false
.......
and we can use it the following way
ListWithoutSepatorsAndMargins {
ForEach(0..<5) { _ in
Text("Content")
}
}
ListWithoutSepatorsAndMargins {
Group {
self.groupSearchResults()
self.myGroups()
self.exploreGroups()
}
}
}
Solution 10:[10]
Here is my solution for iOS 14:
struct MyRowView: View {
var body: some View {
ZStack(alignment: .leading) {
// Background color of the Row. It will spread under the entire row.
Color(.systemBackground)
NavigationLink(destination: Text("Details")) {
EmptyView()
}
.opacity(0) // Hide the Disclosure Indicator
Text("Go to Details").padding(.leading)
}
// These 2 lines hide the row separators
.padding(.horizontal, -16) // Removes default horizontal padding
.padding(.vertical, -6) // Removes default vertical padding
}
}
The enclosing List should have this modifier
.listStyle(PlainListStyle())
The upside of this solution over using a LazyVStack is that you can still use the Edit capabilities of the List.
This solution relies unfortunately on hard-coded values to remove the system default paddings on each row. Hopefully SwiftUI 3.0 will provide simple .separatorStyle(.none) and .accessoryType(.none) modifiers.
The code to remove the Disclosure Indicators comes from: https://www.appcoda.com/hide-disclosure-indicator-swiftui-list/
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | average Joe |
| Solution 4 | Mark Phillips |
| Solution 5 | |
| Solution 6 | Tzegenos |
| Solution 7 | Senseful |
| Solution 8 | Ehsan Askari |
| Solution 9 | Harish saini |
| Solution 10 |

