UIAppearance
properties
iOS development
user interface
proxy

What properties can I set via an UIAppearance proxy?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

You cannot set arbitrary properties through a UIAppearance proxy. Only appearance-customizable selectors exposed by a UIKit class are supported. In practice, that means the property or setter must be specifically marked by the framework as appearance-capable, and if you are unsure, the safest rule is simple: if the compiler lets you call it on SomeView.appearance(), that property is supported for that class.

What UIAppearance Is For

UIAppearance lets you define styling rules once and have them applied to matching UIKit components throughout the app.

Common examples include:

  • navigation bar title attributes
  • tab bar tint colors
  • segmented control colors
  • bar button title text attributes

Example:

swift
1import UIKit
2
3let navBarAppearance = UINavigationBar.appearance()
4navBarAppearance.tintColor = .systemBlue
5navBarAppearance.barTintColor = .white
6navBarAppearance.titleTextAttributes = [
7    .foregroundColor: UIColor.black
8]

These are classic examples of properties specifically designed for appearance customization.

Not Every Property Is Appearance-Customizable

A major point of confusion is assuming that because a property exists on a UIKit class, it can be set globally via appearance. That is not true.

For example, a view’s runtime state, frame, current text content, or arbitrary internal property is not something UIAppearance is meant to control.

UIAppearance is for style-related configuration that the framework has explicitly exposed through appearance selectors.

Practical Rule: Check the Proxy Type

When you call .appearance(), Xcode will only offer the appearance-capable API surface for that type.

swift
let buttonAppearance = UIButton.appearance()
buttonAppearance.tintColor = .systemRed

If you try to call something unsupported through the appearance proxy, it will typically not compile.

This is often the most pragmatic answer: let the framework’s type system tell you what is available for that class.

Examples of Commonly Supported Properties

Some well-known appearance-driven properties include:

swift
1UILabel.appearance().textColor = .darkGray
2UISwitch.appearance().onTintColor = .systemGreen
3UITabBar.appearance().tintColor = .systemBlue
4UITextField.appearance().tintColor = .systemOrange

Support varies by class. The fact that textColor is appearance-customizable for one class does not mean every analogous property on every other class is.

Container-Specific Appearance

UIAppearance can also scope styles by containment. That lets you style controls differently when they appear inside a specific container hierarchy.

swift
let buttonAppearance = UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self])
buttonAppearance.tintColor = .white

This is useful when global styling is too broad and you need context-specific theming.

Timing Matters

Appearance rules should usually be applied early in application startup, before the affected views are created.

For example:

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        UINavigationBar.appearance().tintColor = .systemBlue
10        return true
11    }
12}

If views already exist, changing the appearance proxy later may not update them the way you expect.

Modern iOS Note

For some UIKit components, especially bars and navigation surfaces, newer dedicated appearance objects such as UINavigationBarAppearance provide more precise control than the older global-proxy model alone.

Example:

swift
1let appearance = UINavigationBarAppearance()
2appearance.configureWithOpaqueBackground()
3appearance.backgroundColor = .white
4appearance.titleTextAttributes = [.foregroundColor: UIColor.black]
5
6UINavigationBar.appearance().standardAppearance = appearance
7UINavigationBar.appearance().scrollEdgeAppearance = appearance

When a component has a newer appearance API, that is often the better customization surface.

What About Custom Views

For your own custom views, appearance-style support is not automatic just because the view subclasses UIView. The property setter has to participate in Objective-C-style selector dispatch and be designed for appearance usage. In practice, this is one reason teams often prefer explicit theme injection or view configuration over leaning too heavily on global appearance behavior for custom components.

That is not a reason to avoid UIAppearance entirely. It is a reason to keep its scope realistic.

Common Pitfalls

The main mistake is assuming every property on a UIKit control is valid through the appearance proxy. Another is applying appearance rules after views have already been created and then wondering why nothing changes. Developers also often try to use UIAppearance for per-instance behavior or runtime state, which it was never designed to manage. Finally, some modern UIKit styling tasks are better handled through newer dedicated appearance objects rather than the older global proxy alone.

Summary

  • You can set only appearance-supported properties through a UIAppearance proxy.
  • If a call works on .appearance() and compiles, that property is supported for that class.
  • 'UIAppearance is meant for styling, not arbitrary runtime state.'
  • Apply appearance configuration early in app startup.
  • Prefer newer dedicated appearance objects where UIKit provides them.

Course illustration
Course illustration

All Rights Reserved.