Mocking iOS 15 Section Headers
How to fake iOS 15's default list section header styles
With the release of iOS 15, you might have noticed that the list header style changes slightly. It now has significantly more padding above and below the section. You can see a comparison below.
iOS 14 List vs. iOS 15 List

If you’re not a fan of this change you can change the headers top padding by changing the sectionHeaderTopPadding
property on a UITableView
or if you’re like me and moved to SwiftUI, then you can use an appearance modifier like so:
UITableView.appearance().sectionHeaderTopPadding = 0
This is all dandy if you want to use lists in your app. You get an (arguably) nice UI tweak for lists, basically for free. But I came across an interesting problem recently when trying to replicate the new style.
Replicating iOS Section Headers
Why would you want to replicate it you ask? Well while working on my latest project (Flora — check it out here), I needed to use a grid in my app as well. I had a ScrollView
with a LazyVGrid
inside it with a bunch of cells that needed to be separated out into sections by category.
Without the context of a list, section headers default to a completely different font size & weight. Keeping with the same list content as the first example, you can see the “Fruits” and “Vegetables” headers now default to the same default text as a regular Text
view.

I wanted to keep a consistent header style across both List
views aswell as any ScrollView
or LazyVGrid
views. Since the user is already likely familiar with the iOS style headers, I thought it’s best to try and mock the iOS Style of header.
… But There’s a Problem
Easier said than done though, as Apple documentation including both SwiftUI and UIKit List
/ UITableView
views do not expose any useful information about default padding, fonts, or colours.
According to the Apple docs, the default value for sectionHeaderTopPadding
is UITableViewAutomaticDimension
. Apple Documentation
This doesn’t help us though because neither the official documentation nor exploring the header file gives us any useful information. It must be determined at run time based on the view's context. There’s also no mention of default font size, font weight or font color for the headers either.
With no official source for the default values, we have to turn to trial and error. First I created a regular old list in SwiftUI, ran it on the simulator, and took a screenshot. Now we have a baseline to compare our own implementation to.
First I started with the distance between the top of the header text and the bottom of the section above, in pixels (see below).
Then I started testing values for padding above the text, taking screenshots as I went, until I got results that were within a few pixels of each other. At that point, I knew I’d found a value that more or less matched Apple's implementation.
The font color is pretty clearly Color.secondary
which seemed to match spot on. Then for font size, more trial, and error. The font that seemed to match closest was a size of 13 points and a .regular
font weight.

Implementation
Putting this all together, we can create a generic view that mocks Apple's implementation.
Here’s all the values I found from some trial and error
- The font color:
Color.secondary
- The font size:
13 Points
- The font weight:
.regular
- Leading padding (Padding from the left side of the list row):
14
- Top padding:
12
- Bottom padding:
8
Putting all these values into a nice generic view, we end up with something like this:
You can then use this view in your own ScrollView
with something like this:
Section(header: MockedSectionHeader(header: "Fruits")) {
Text("Apple")
Text("Orange")
Text("Pear")
}
You may have to add padding to the sides of the LazyVGrid
or ScrollView
you are using to match a List
side padding but now we’ve pretty much matched the iOS header style as close as we can.
This was useful in my own project so if you have the same issue, hopefully, I’ve saved you some time googling & tinkering.
Thanks for reading.