How to Create a Button in SwiftUI

What you’ll build or solve

Create a button in SwiftUI by using the Button view with a label and an action. You’ll define a button using either the simple text initializer or the custom label initializer.

When this approach works best

Creating a button in SwiftUI works best when:

  • You need to trigger an action, such as saving data or navigating.
  • You want a reusable control inside a custom view.
  • You need either a simple text button or a button with custom layout.

This is a bad idea if you need advanced gestures like drag or long press with complex state handling. In that case, use gesture modifiers instead.

Prerequisites

  • Xcode with a SwiftUI project
  • Basic understanding of SwiftUI views

Step-by-step instructions

Step 1: Create a button with a text label

Use the Button initializer that takes a string and an action closure.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Button("Tap Me") {
            print("Button tapped")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

The first parameter is the button’s label. The closure runs when the button is tapped.

Step 2: Create a button with a custom label

Use the Button(action:label:) initializer to build a custom label view.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Button(action: {
            print("Custom button tapped")
        }) {
            HStack {
                Image(systemName: "star.fill")
                Text("Favorite")
            }
        }
        .padding()
    }
}

This form allows you to combine text, images, and layout inside the label.

What to look for

  • The action closure is required.
  • The custom label can contain any SwiftUI view.
  • You can later connect the action to @State, @Binding, or a model.
  • You can apply styling using modifiers like .buttonStyle() or .padding().

Examples you can copy

Example 1: Simple print action

import SwiftUI

struct SimpleButtonView: View {
    var body: some View {
        Button("Log Message") {
            print("Log button tapped")
        }
    }
}

Example 2: Button with icon and text

import SwiftUI

struct IconTextButtonView: View {
    var body: some View {
        Button(action: {
            print("Share tapped")
        }) {
            HStack {
                Image(systemName: "square.and.arrow.up")
                Text("Share")
            }
        }
    }
}

Example 3: Custom layout inside label

import SwiftUI

struct ComplexLabelButtonView: View {
    var body: some View {
        Button(action: {
            print("Profile tapped")
        }) {
            VStack {
                Image(systemName: "person.circle")
                    .font(.largeTitle)
                Text("Profile")
            }
        }
    }
}

The label can use stacks, images, text, or any other SwiftUI view.

Common mistakes and how to fix them

Mistake 1: Forgetting the action closure

What you might do:

Button("Tap Me")

Why it breaks: Button requires an action closure, so this will not compile.

Correct approach:

Button("Tap Me") {
    print("Tapped")
}

Mistake 2: Mixing up initializer syntax

What you might do:

Button("Tap Me", action: {
    print("Tapped")
}) {
    Text("Label")
}

Why it breaks: You are combining both initializer forms in one declaration.

Correct approach: Use one form only.

Text-only form:

Button("Tap Me") {
    print("Tapped")
}

Custom label form:

Button(action: {
    print("Tapped")
}) {
    Text("Tap Me")
}

Troubleshooting

  • If you see a compiler error about missing parameters, confirm you provided an action closure.
  • If the label does not appear, check that your custom label returns a valid SwiftUI view.
  • If the button does not respond, confirm your action closure contains executable code.
  • If previews fail, verify the view compiles independently before embedding it elsewhere.

Quick recap

  • Use Button("Title") { action } for a simple text button.
  • Use Button(action:) { label } for custom layouts.
  • Provide an action closure every time.
  • Keep initializer forms separate, do not mix them.
  • Build labels with any SwiftUI view.