iOS development
UIPageControl customization
pagination dots
Swift programming
mobile app design

How can I change the color of pagination dots of UIPageControl?

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

UIPageControl is a common pagination indicator used in onboarding and swipeable content flows. Changing dot colors is straightforward, but behavior can vary depending on iOS version, appearance APIs, and whether UIKit or SwiftUI hosts the control. A robust implementation sets colors directly, handles current page updates, and optionally configures global appearance.

Basic Dot Color Customization

The two key properties are:

  • pageIndicatorTintColor for inactive dots.
  • currentPageIndicatorTintColor for active dot.
swift
1import UIKit
2
3let pageControl = UIPageControl()
4pageControl.numberOfPages = 5
5pageControl.currentPage = 0
6
7pageControl.pageIndicatorTintColor = UIColor.systemGray4
8pageControl.currentPageIndicatorTintColor = UIColor.systemBlue

Set both properties to avoid default mixed styling.

Full Example in a View Controller

swift
1import UIKit
2
3final class OnboardingViewController: UIViewController {
4    private let pageControl = UIPageControl()
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        view.backgroundColor = .systemBackground
9
10        pageControl.translatesAutoresizingMaskIntoConstraints = false
11        pageControl.numberOfPages = 4
12        pageControl.currentPage = 0
13        pageControl.pageIndicatorTintColor = .systemGray3
14        pageControl.currentPageIndicatorTintColor = .systemRed
15
16        view.addSubview(pageControl)
17
18        NSLayoutConstraint.activate([
19            pageControl.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -24),
20            pageControl.centerXAnchor.constraint(equalTo: view.centerXAnchor)
21        ])
22    }
23
24    func updatePage(index: Int) {
25        pageControl.currentPage = index
26    }
27}

Link updatePage to your scroll-view paging logic.

UIAppearance for App-Wide Styling

If many screens use UIPageControl, set a shared appearance.

swift
UIPageControl.appearance().pageIndicatorTintColor = .systemGray4
UIPageControl.appearance().currentPageIndicatorTintColor = .systemGreen

Use this carefully, because it affects every page control in the app unless scoped through containment APIs.

Dynamic Color and Dark Mode

Use dynamic system colors or custom trait-aware colors.

swift
1pageControl.pageIndicatorTintColor = UIColor { trait in
2    trait.userInterfaceStyle == .dark ? .lightGray : .darkGray
3}
4
5pageControl.currentPageIndicatorTintColor = UIColor { trait in
6    trait.userInterfaceStyle == .dark ? .systemYellow : .systemBlue
7}

Dynamic colors keep contrast readable in both light and dark appearances.

iOS 14 Plus Indicator Images

Recent iOS versions allow custom indicator images for more control than plain tint colors.

swift
1if #available(iOS 14.0, *) {
2    let image = UIImage(systemName: "circle.fill")
3    pageControl.preferredIndicatorImage = image
4}

You can also set per-page indicator image if design requires special markers.

Runtime Theme Switching

If your app supports in-app theme changes, update page-control colors when theme state changes instead of setting them once in viewDidLoad.

swift
1func applyTheme(_ theme: Theme) {
2    pageControl.pageIndicatorTintColor = theme.inactiveDot
3    pageControl.currentPageIndicatorTintColor = theme.activeDot
4}

Call this during theme notifications so pagination style stays synchronized across screens.

SwiftUI Interop

In SwiftUI, PageTabViewStyle uses page indicators that can be customized with appearance proxies.

swift
1import SwiftUI
2
3struct PagerView: View {
4    init() {
5        UIPageControl.appearance().pageIndicatorTintColor = .lightGray
6        UIPageControl.appearance().currentPageIndicatorTintColor = .systemBlue
7    }
8
9    var body: some View {
10        TabView {
11            Color.red
12            Color.green
13            Color.blue
14        }
15        .tabViewStyle(PageTabViewStyle())
16    }
17}

Be aware that appearance changes are global across SwiftUI views sharing the same process.

Storyboard and Interface Builder Notes

If your page control comes from storyboard, you can still set colors in viewDidLoad after outlets are connected. Interface Builder may preview one palette while runtime applies another, so always verify final colors on a real device in light and dark modes.

Accessibility and Contrast

Color customization should maintain clear contrast and selection visibility. If active and inactive dots are too similar, pagination state becomes hard to read.

Test with:

  • Light and dark modes.
  • Increased contrast accessibility setting.
  • Different background colors behind page control.

Visual QA matters as much as API correctness. Also verify appearance in right-to-left layouts and larger text settings where surrounding layout can shift page control placement and perceived readability. Consistency across themes improves onboarding polish significantly. Users notice this.

Common Pitfalls

  • Setting only one tint property. Fix by setting both current and inactive dot colors.
  • Applying global appearance unintentionally. Fix by scoping styling to local controls when needed.
  • Choosing low-contrast color pairs. Fix by testing readability in light and dark themes.
  • Forgetting to update currentPage during scroll. Fix by syncing page control in scroll callbacks.
  • Assuming SwiftUI styles are local only. Fix by remembering appearance proxy affects global UIPageControl instances.

Summary

  • Customize dots with pageIndicatorTintColor and currentPageIndicatorTintColor.
  • Use local styling for screen-specific UI and appearance proxy for global themes.
  • Consider dynamic colors for dark mode support.
  • Sync currentPage with page transitions.
  • Validate accessibility contrast before shipping.

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