UITableView
iOS Development
Swift
Separator Color
UITableViewCell

UITableView, Separator color where to set?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

UITableView separator styling looks simple, but the location where you set it affects consistency and reuse. If separator color is configured too late or in multiple places, table views can render with mixed styles across screens. A robust setup defines global defaults when needed and applies screen specific overrides in the owning view controller.

Where to Set Separator Color

You can set separator color in three common places:

  • globally with appearance proxy
  • per table view in viewDidLoad
  • per cell using custom separator views when default behavior is not enough

The right choice depends on whether you need app wide consistency or local customization.

Per Screen Setup in View Controller

Most projects should start with explicit per screen settings in viewDidLoad.

swift
1import UIKit
2
3final class ContactsViewController: UITableViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        tableView.separatorStyle = .singleLine
8        tableView.separatorColor = UIColor.systemGray3
9        tableView.separatorInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
10    }
11}

This keeps behavior local and avoids accidental global style bleed.

Global Default with Appearance Proxy

If your app uses one separator style almost everywhere, set a default in AppDelegate or scene setup.

swift
1import UIKit
2
3@main
4class AppDelegate: UIResponder, UIApplicationDelegate {
5    func application(
6        _ application: UIApplication,
7        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
8    ) -> Bool {
9        UITableView.appearance().separatorColor = UIColor.systemGray4
10        return true
11    }
12}

Then override locally where a screen needs a different visual style.

Removing Partial Separators in Empty Rows

Developers often think separator color is wrong when extra separators appear below real content. Those lines come from empty cells.

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3
4    tableView.tableFooterView = UIView(frame: .zero)
5}

Setting footer view to empty removes separators for unused rows.

Custom Separator for Full Visual Control

Default separators can be limiting if design needs gradients, custom margins, or hidden lines for selected rows. In that case, disable default separators and draw your own.

swift
1final class CustomCell: UITableViewCell {
2    private let line = UIView()
3
4    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
5        super.init(style: style, reuseIdentifier: reuseIdentifier)
6
7        line.translatesAutoresizingMaskIntoConstraints = false
8        line.backgroundColor = .systemTeal
9        contentView.addSubview(line)
10
11        NSLayoutConstraint.activate([
12            line.heightAnchor.constraint(equalToConstant: 1),
13            line.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
14            line.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
15            line.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
16        ])
17    }
18
19    required init?(coder: NSCoder) {
20        fatalError("init(coder:) has not been implemented")
21    }
22}

Controller setup:

swift
tableView.separatorStyle = .none

This gives pixel level control.

Dynamic Theme Support

For dark mode and theme switching, use semantic colors so separators adapt automatically.

swift
tableView.separatorColor = UIColor.separator

If design system provides custom tokens, map them to light and dark variants and reapply in trait change callbacks when needed.

swift
1override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
2    super.traitCollectionDidChange(previousTraitCollection)
3    tableView.separatorColor = UIColor.separator
4}

Debugging Inconsistent Separator Styling

If separator style appears inconsistent, check these first:

  • are you setting color before table view is created
  • is appearance proxy overriding local values
  • are reusable cells adding custom lines that conflict with defaults
  • does grouped style change visual expectations

A quick test is to print properties in viewDidAppear and verify final values.

Common Pitfalls

A common pitfall is setting separator color in cellForRowAt repeatedly. This adds unnecessary work and can still miss global consistency.

Another issue is using hard coded light colors that become invisible in dark mode. Prefer semantic colors or dynamic palettes.

A third issue is mixing default separators and custom separator subviews in one table. Visual duplication is likely unless one approach is disabled.

Developers also forget empty row separators, then chase the wrong styling bug. Remove them with footer setup early.

Summary

  • Set separator color in view controller for local control
  • Use appearance proxy only for intentional app wide defaults
  • Remove extra empty row separators with empty footer view
  • Use custom separator views when design needs full control
  • Prefer semantic colors for reliable light and dark mode behavior

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.