SwiftUI: How to make TextEditor field tabbable on MacOS

229 Views Asked by At

I have a two text fields on my View. I want to be able to tab between them. It is currently writing the tab into the text content.

struct MyView: View
{
    @State var field1: String
    @State var field2: String

    var body: some View
    {
         TextEditor(text: $field1)
            .disableAutocorrection(false)
            .fixedSize(horizontal: false, vertical: true)
            .font(Font.system(size: 22, weight: .medium, design: .default))
            .multilineTextAlignment(.leading)
            .lineLimit(3)
            .overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 1)

        TextEditor(text: $field2)
            .disableAutocorrection(false)
            .fixedSize(horizontal: false, vertical: true)
            .font(Font.system(size: 22, weight: .medium, design: .default))
            .multilineTextAlignment(.leading)
            .lineLimit(3)
            .overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 1)
    }
}

How do I make the tab jump to the next field? Do I manually need to manage the focus or is there a simpler way?

1

There are 1 best solutions below

4
Pixel Paras On

You can use the focusable() modifier. The focusable() modifier makes a view focusable, which means that it can be selected using the tab key. (This I what makes the tab jump to the next field)

Here's an updated version of your code that demonstrates how to make the text fields tabbable:

struct MyView: View {
    @State private var field1: String = ""
    @State private var field2: String = ""
    
    @FocusState private var isField1Focused: Bool
    @FocusState private var isField2Focused: Bool
    
    var body: some View {
        VStack {
            TextEditor(text: $field1)
                .focusable(isField1Focused) { focused in
                    isField1Focused = focused
                }
                .disableAutocorrection(false)
                .fixedSize(horizontal: false, vertical: true)
                .font(Font.system(size: 22, weight: .medium, design: .default))
                .multilineTextAlignment(.leading)
                .lineLimit(3)
                .overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 1))
            
            TextEditor(text: $field2)
                .focusable(isField2Focused) { focused in
                    isField2Focused = focused
                }
                .disableAutocorrection(false)
                .fixedSize(horizontal: false, vertical: true)
                .font(Font.system(size: 22, weight: .medium, design: .default))
                .multilineTextAlignment(.leading)
                .lineLimit(3)
                .overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 1))
        }
        .onAppear {
            isField1Focused = true // Set the initial focus to field1
        }
    }
}

The two @FocusState properties, isField1Focused and isField2Focused represent the focus state of each text field, And the focusable modifier is applied to each text field, specifying the corresponding @FocusState property and updating it when the focus is changed.

.onAppear modifier is used to set isField1Focused to true, making the first text field active when the view emerges.

If the user presses the Tab key, the focus will automatically move between the text fields, allowing it to switch from one to the other without inserting a tab character into the content.