Search code examples
iosswiftswiftuitextfieldtext-alignment

SwiftUI TextField with vertical axis does not align to firstTextBaseline when text is empty


I have a difficult time to find a workaround to align multiline TextField with another Text in HStack. I want to align it firstTextBaseline. The problem is, TextField jumps down when its text becomes empty and only the placeholder is shown.

I use these HStack in the List rows, but the alignment does not work even in the stripped and simplified code like this:

struct TextFieldAlignmentProblem: View {
    
    @State private var text: String = ""
    
    var body: some View {
        HStack(alignment: .firstTextBaseline) {
            Text("1")
            TextField("Text", text: $text, axis: .vertical)
        }
        .padding()
    }
}

TextField jumps down when its text becomes empty and only the placeholder is shown.

If I remove axis: .vertical or use .center alignment instead of .firstTextBaseline, the jumping problem disappears, but that is not the layout I need.

The problem looks quite simple, but I failed to find a suiting solution for now.


Solution

  • Unfortunately, it's a bug that happens on the axis: .vertical when the field is empty.

    ✅ Perfect Solution:

    You can make a placeholder to hold the textfield in the correct position:

    struct TextFieldAlignmentProblem: View {
    
        @State private var text: String = ""
        private var placeholder: String { text.isEmpty ? " " : text } // 👈 Generate a correct placeholder. I have used a single space.
    
        var body: some View {
            HStack(alignment: .firstTextBaseline) {
                Text("1")
    
                TextField("Text", text: .constant(placeholder), axis: .vertical) // 👈 Use the placeholder as the base
                    .opacity(0) // 👈 Make it hidden keeping the frame
                    .overlay { // 👈 Put the actual TextField on top of the placeholder view
                        TextField("Text", text: $text, axis: .vertical)
                    }
            }
            .padding()
        }
    }
    

    💡 Simple Solution:

    If you are not going to use different fonts, typefaces, dynamic types, etc, a very simple and quick workaround could be checking the condition and passing the (visually) correct alignment:

    HStack(
        alignment: text.isEmpty ? .center : .firstTextBaseline // 👈 Conditional alignment
    ) { ,,, }