SwiftUI
Button Design
Corner Radius
User Interface
Swift Programming

Button border with corner radius in Swift UI

Master System Design with Codemia

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

Introduction

In SwiftUI, a button border with rounded corners is usually built by combining background, overlay, and shape modifiers. The order of these modifiers determines whether the border follows the corner radius correctly. A clean style requires both visual consistency and touch friendly interaction.

Build a Reusable Rounded Border Button

The most maintainable approach is a custom ButtonStyle. This keeps design logic in one place and makes the same border behavior reusable across screens.

swift
1import SwiftUI
2
3struct RoundedBorderButtonStyle: ButtonStyle {
4    var borderColor: Color = .blue
5    var fillColor: Color = .white
6    var cornerRadius: CGFloat = 12
7
8    func makeBody(configuration: Configuration) -> some View {
9        configuration.label
10            .font(.headline)
11            .padding(.vertical, 12)
12            .padding(.horizontal, 18)
13            .background(
14                RoundedRectangle(cornerRadius: cornerRadius)
15                    .fill(fillColor)
16            )
17            .overlay(
18                RoundedRectangle(cornerRadius: cornerRadius)
19                    .stroke(borderColor, lineWidth: 2)
20            )
21            .opacity(configuration.isPressed ? 0.75 : 1.0)
22            .animation(.easeOut(duration: 0.15), value: configuration.isPressed)
23    }
24}
25
26struct ContentView: View {
27    var body: some View {
28        Button("Save") {
29            print("Saved")
30        }
31        .buttonStyle(RoundedBorderButtonStyle())
32    }
33}

This code provides clear press feedback and keeps the border radius aligned with the background shape.

Modifier Order Matters

A common visual bug appears when cornerRadius is applied after a rectangular overlay stroke. The border can stay square while the fill is rounded. Using the same RoundedRectangle shape for both fill and stroke avoids that mismatch.

If you need clipping for complex backgrounds, apply clipShape with the same radius value used in overlay. Consistent shape definitions prevent edge artifacts on high density screens.

Adapting Style for Disabled and Themed States

Production buttons need state aware styling. Disabled state should lower contrast and reduce emphasis without removing legibility. Dark mode support should preserve accessible contrast ratios.

swift
1import SwiftUI
2
3struct ThemedActionButton: View {
4    let title: String
5    let isEnabled: Bool
6    let action: () -> Void
7
8    var body: some View {
9        Button(title, action: action)
10            .buttonStyle(
11                RoundedBorderButtonStyle(
12                    borderColor: isEnabled ? .accentColor : .gray,
13                    fillColor: isEnabled ? Color(.systemBackground) : Color(.systemGray6),
14                    cornerRadius: 14
15                )
16            )
17            .disabled(!isEnabled)
18    }
19}

Keep padding generous so the tappable area remains comfortable. Touch targets that only fit text width may pass visual review but fail usability in real usage.

Alternative with Capsule or Custom Shapes

If your design calls for pill style buttons, replace RoundedRectangle with Capsule. For brand specific corners, create a custom Shape implementation and use it consistently in both background and overlay.

The same principle still applies: one shared shape definition for fill and stroke yields predictable results.

Use SwiftUI previews to validate style at multiple dynamic type sizes and color schemes. Border thickness and corner smoothness can look different when text scales up, so include large accessibility text previews in your design review. Catching these issues in preview is much faster than adjusting style after QA feedback. You can also snapshot test key button states to prevent regressions when design tokens or spacing constants are updated later in the release cycle. This is especially valuable in apps with shared design systems used by many teams.

Common Pitfalls

A frequent pitfall is applying .border modifier directly and expecting rounded corners. .border draws a rectangular border and does not follow corner radius.

Another issue is defining different corner radii for background and overlay. Even a small mismatch can produce blurry or clipped corners.

Developers also forget disabled styling and rely only on opacity. In some themes this can reduce readability too much. Add explicit disabled colors.

Finally, animations that trigger on every render can cause flicker. Limit state driven animations to press state changes or explicit transitions.

Summary

  • Use a custom ButtonStyle for reusable rounded border behavior.
  • Draw fill and border with the same rounded shape to avoid mismatches.
  • Respect modifier order, especially with overlay and clipping.
  • Add clear disabled and dark mode aware styles.
  • Prefer shape based borders over .border for rounded designs.

Course illustration
Course illustration

All Rights Reserved.