user7649191
user7649191

Reputation:

Disabling macOS focus ring in SwiftUI

Is it possible to disable the focus ring around a TextField in swiftUI for Mac?

Upvotes: 8

Views: 1957

Answers (3)

TheNeil
TheNeil

Reputation: 3742

As stated in an answer by Asperi to a similar question here, it's not possible (before iOS 17 / macOS 14) to turn off the focus ring for a specific field using SwiftUI; however, the following workaround will disable the focus ring for all NSTextField instances in the app:

extension NSTextField {
    open override var focusRingType: NSFocusRingType {
        get { .none }
        set { }
    }
}

Not ideal, but it does provide one option that doesn't require stepping too far outside of SwiftUI.

Upvotes: 5

TheNeil
TheNeil

Reputation: 3742

As identified by George Valkov in this question, as of iOS 17 / macOS 14, you can apply .focusEffectDisabled to specific sub-views or an entire view.

TextField("Search", text: self.$searchText)
.focusEffectDisabled()

Upvotes: 2

Christophe Bronner
Christophe Bronner

Reputation: 71

I had that question as well, and after a couple hours of fiddling around, it seems like the answer is no. However, it is possible to wrap an NSTextField and get rid of the focus ring.

The following code has been tested in the latest release.

struct CustomTextField: NSViewRepresentable {
    @Binding var text: String

    init(text: Binding<String>) {
        _text = text
    }

    func makeNSView(context: Context) -> NSTextField {
        let textField = NSTextField(string: text)
        textField.delegate = context.coordinator
        textField.isBordered = false
        textField.backgroundColor = nil
        textField.focusRingType = .none
        return textField
    }

    func updateNSView(_ nsView: NSTextField, context: Context) {
        nsView.stringValue = text
    }

    func makeCoordinator() -> Coordinator {
        Coordinator { self.text = $0 }
    }

    final class Coordinator: NSObject, NSTextFieldDelegate {
        var setter: (String) -> Void

        init(_ setter: @escaping (String) -> Void) {
            self.setter = setter
        }

        func controlTextDidChange(_ obj: Notification) {
            if let textField = obj.object as? NSTextField {
                setter(textField.stringValue)
            }
        }

    }

}

Upvotes: 7

Related Questions