How to add clear button in TextField

DevTechie Inc
Jan 29, 2023

SwiftUI TextField provides many functionalities out of the box but if you are looking for clear button similar to what UIKit version of TextField provides, you will not find it as its not available. At least without adding extra bit of code.

In this article, we will look at two ways of bringing clear button back into the SwiftUI’s TextField.

First Approach — UITextField
For the first approach, we will look into UITextField’s appearance object. Since TextField is backed by UITextField, we can enable clear button from its appearance object by setting it in init, as shown below:

struct DevTechieTextFieldClearButtonExample: View {
    
    @State private var text = ""
    
    init() {
        UITextField.appearance().clearButtonMode = .whileEditing
    }
    
    var body: some View {
        VStack {
            Text("DevTechie")
                .font(.largeTitle)
            
            TextField("Enter something", text: $text)
                .textFieldStyle(.roundedBorder)
        }
        .padding()
    }
}
This is the easiest way but let’s say that we want to customize the button for look and feel or functionality etc, in that case let’s jump on the second approach.

Second Approach — View Modifier Way
For the second approach we will build our own ViewModifier and build this functionality from scratch. You may wonder why? Well in case you need more control over what happens in the clear button or want to track cleared values to build your own undo manager, in these cases custom implementation will give you more control.

We will start with a new struct and call it ClearButton. This struct will extend ViewModifier protocol. Which allows us to create custom modifiers so we can apply them to a view or another view modifier, producing a different version of the original value.

struct ClearButton: ViewModifier { }
This ViewModifier will accept text string as a binding property.

@Binding var text: String
ViewModifier has only one requirement, which is to implement body function. Body function gives us access to content on which the modifier will be applied. Body function returns some View type.

func body(content: Content) -> some View { }
Inside the body, we will add a ZStack with trailing alignment. ZStack will host content along with a conditional check. Conditional check will be to display the clear button or not. We don’t want to display clear button when text is empty and conditional if statement will help us with this.

Clear button’s action will be to empty out the binding text.

ZStack(alignment: .trailing) {
    content
    
    if !text.isEmpty {
        Button {
            text = ""
        } label: {
            Image(systemName: "multiply.circle.fill")
                .foregroundStyle(.gray)
        }
        .padding(.trailing, 8)
    }
}
We will add a convenience function as an extension to the View, which will call our custom modifier by passing the provided binding text string.

extension View {
    func clearButton(text: Binding<String>) -> some View {
        modifier(ClearButton(text: text))
    }
}
Our complete ClearButton.swift file will look like this:

struct ClearButton: ViewModifier {
    @Binding var text: String
    
    func body(content: Content) -> some View {
        ZStack(alignment: .trailing) {
            content
            
            if !text.isEmpty {
                Button {
                    text = ""
                } label: {
                    Image(systemName: "multiply.circle.fill")
                        .foregroundStyle(.gray)
                }
                .padding(.trailing, 8)
            }
        }
    }
}extension View {
    func clearButton(text: Binding<String>) -> some View {
        modifier(ClearButton(text: text))
    }
}
Our modifier is ready to be used. Let’s create a view and attach this new modifier to a TextField.

struct DevTechieTextFieldClearButtonExample: View {
    
    @State private var text = ""
    
    var body: some View {
        VStack {
            Text("DevTechie")
                .font(.largeTitle)
            
            TextField("Enter something", text: $text)
                .textFieldStyle(.roundedBorder)
                .clearButton(text: $text)
        }
        .padding()
    }
}
We can customize this clear button like any other view. Let’s change the Image for the button along with the foregroundStyle.

Image(systemName: "delete.backward.fill").foregroundStyle(.orange.gradient.opacity(0.6))
With that we have reached the end of this article. Thank you once again for reading. If you liked this, don’t forget to 👏 and follow 😍. Also subscribe to our weekly newsletter at https://www.devtechie.com