Swift
UIButton
iOS Development
Programming
Code Tutorial

Make a UIButton programmatically in Swift

Master System Design with Codemia

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

Introduction

Creating a UIButton in code is useful when the UI is dynamic, when you want reusable view components, or when you prefer code-based layout over storyboards. The basic process is simple: create the button, configure its appearance, wire up an action, and add constraints so it appears where you expect.

Creating the Button

The most direct starting point is UIButton(type:). A system button gives you platform-consistent behavior and styling defaults.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    private let button = UIButton(type: .system)
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        view.backgroundColor = .systemBackground
9
10        button.setTitle("Tap Me", for: .normal)
11        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
12
13        view.addSubview(button)
14    }
15
16    @objc private func buttonTapped() {
17        print("Button tapped")
18    }
19}

At this point the button exists and responds to taps, but it still needs layout before it appears in a useful place.

Laying Out the Button with Auto Layout

If you create views in code, you almost always want Auto Layout instead of hard-coded frames. The important setup step is disabling the autoresizing-mask translation.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    private let button = UIButton(type: .system)
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        view.backgroundColor = .systemBackground
9
10        button.setTitle("Continue", for: .normal)
11        button.translatesAutoresizingMaskIntoConstraints = false
12        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
13
14        view.addSubview(button)
15
16        NSLayoutConstraint.activate([
17            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
18            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
19            button.heightAnchor.constraint(equalToConstant: 50),
20            button.widthAnchor.constraint(greaterThanOrEqualToConstant: 140)
21        ])
22    }
23
24    @objc private func buttonTapped() {
25        print("Continue tapped")
26    }
27}

This is the pattern to remember: create, add as a subview, disable autoresizing translation, and then activate constraints.

Styling the Button

You can style a button with the older property-based API or the newer configuration API. For modern iOS work, UIButton.Configuration is often the cleaner choice.

swift
1import UIKit
2
3let button = UIButton(type: .system)
4var config = UIButton.Configuration.filled()
5config.title = "Save"
6config.baseBackgroundColor = .systemBlue
7config.baseForegroundColor = .white
8config.cornerStyle = .large
9config.image = UIImage(systemName: "tray.and.arrow.down.fill")
10config.imagePadding = 8
11
12button.configuration = config

This approach keeps visual settings together in one place and avoids manually coordinating title color, insets, background, and image spacing.

If you only need basic styling, the older API is still valid:

swift
1button.setTitle("Delete", for: .normal)
2button.setTitleColor(.white, for: .normal)
3button.backgroundColor = .systemRed
4button.layer.cornerRadius = 10
5button.contentEdgeInsets = UIEdgeInsets(top: 12, left: 20, bottom: 12, right: 20)

Choosing an Action Style

The traditional pattern uses addTarget and an @objc selector. That is still common and works across many UIKit codebases. If you are targeting newer iOS versions, UIAction can be a nice alternative for inline behavior.

swift
1import UIKit
2
3let button = UIButton(type: .system)
4button.configuration = .filled()
5button.configuration?.title = "Run"
6
7button.addAction(UIAction { _ in
8    print("Run tapped")
9}, for: .touchUpInside)

For reusable controls inside larger view controllers, UIAction can make short button behavior easier to read. For more established UIKit patterns or older deployment targets, selectors remain perfectly fine.

Reusing Button Setup

If several screens use the same visual style, create a helper instead of duplicating configuration everywhere.

swift
1import UIKit
2
3func makePrimaryButton(title: String) -> UIButton {
4    let button = UIButton(type: .system)
5    var config = UIButton.Configuration.filled()
6    config.title = title
7    config.cornerStyle = .large
8    config.baseBackgroundColor = .systemIndigo
9    config.baseForegroundColor = .white
10    button.configuration = config
11    return button
12}
13
14let primaryButton = makePrimaryButton(title: "Checkout")

That keeps color, shape, and spacing consistent across the app.

Common Pitfalls

  • Forgetting view.addSubview(button), which means the button never enters the view hierarchy.
  • Adding constraints without setting translatesAutoresizingMaskIntoConstraints = false.
  • Using .touchDown when you really want standard tap behavior from .touchUpInside.
  • Mixing heavy manual styling with UIButton.Configuration and then wondering which settings take effect.
  • Capturing too much view-controller state in a UIAction closure when a selector would be clearer.

Summary

  • Create a button with UIButton(type:), then configure title, appearance, and behavior.
  • Add it to the view hierarchy before expecting it to render.
  • Use Auto Layout for predictable placement in code-based interfaces.
  • 'UIButton.Configuration is a strong default for modern UIKit styling.'
  • Choose either selectors or UIAction based on the deployment target and the complexity of the interaction.

Course illustration
Course illustration

All Rights Reserved.