Home > Software engineering >  SwiftUI custom TextField with focus ring on macOS
SwiftUI custom TextField with focus ring on macOS

Time:07-21

I want to have my custom TextField style on macOS, that also has the focus ring

however i am running into 2 issues, depending if i use .textFieldStyle(.roundedBorder) or .textFieldStyle(.plain)

struct FTextFieldStyle: TextFieldStyle {
    func _body(configuration: TextField<Self._Label>) -> some View {
        configuration
            .textFieldStyle(.roundedBorder)
            .frame(maxWidth: .infinity)
            .padding(6)
            .foregroundColor(Color.black)
            .background(Color.white)
            .cornerRadius(6)
            .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 0.5)
            .focusable()
    }
}

TextField("E-mail", text: $email).textFieldStyle(FTextFieldStyle())

When using .roundedBorder

  1. the focus ring is misalligned

  2. the "bezel" cannot be removed

enter image description here

When using .plain

  • i cannot restore the focus ring functionality, even by adding .focusable(), the focus ring is gone

enter image description here

So how to have a custom TextField that has the system focus ring?

CodePudding user response:

You can create a custom focus ring using @FocusState & .overlay:

struct FTextFieldStyle: TextFieldStyle {
    @FocusState var isFocused: Bool
    func _body(configuration: TextField<Self._Label>) -> some View {
        configuration
            .textFieldStyle(.plain)
            .frame(maxWidth: .infinity)
            .padding(6)
            .foregroundColor(Color.black)
            .background(Color.white)
            .cornerRadius(6)
            .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 0.5)
            .focusable()
            .focused($isFocused)
            .overlay(RoundedRectangle(cornerRadius: 6).stroke(Color.accentColor.opacity(0.5), lineWidth: 4).opacity(isFocused ? 1 : 0).scaleEffect(isFocused ? 1 : 1.04))
            .animation(isFocused ? .easeIn(duration: 0.2) : .easeOut(duration: 0.0), value: isFocused)
    }
}
  • Related