SwiftUI Multi-line Text Fields

A SwiftUI text field defaults to a single line that scrolls horizontally when needed. Starting with iOS 16, you can have it expand to a vertically scrolling, multi-line text field. Here’s what you need to know.

Text Fields

According to the Apple HIG, you use a text field for user input when you want a small amount of information such as a name or email address. For large amounts of text you use a text view (or TextEditor if you’re working with SwiftUI):

Form {
  Section("Your details") {
    TextField("email", text: $email)
      .textInputAutocapitalization(.never)
      .autocorrectionDisabled(true)
  }
  Section("Feedback") {
    TextEditor(text: $text)
  }
}

iPhone 14 Pro showing feedback form with email and feedback input fields on cyan background

I’ve never liked the way text fields work when the content gets too big to fit in the available space. Using a SwiftUI TextField as you type beyond the field width the input text scrolls horizontally:

email text field, with cursor on right, showing h.harrison@a.very.long.domain.name

In some situations, I would prefer if the text field could extend over several lines.

Multi-line Text Fields

In iOS 16, you can specify an axis for the direction the text will scroll in when it fills the space. To have the text field scroll vertically:

TextField("email", text: $email, axis: .vertical)

Long email address wrapped over two lines. Email is keith.harrison@a.very.long.domain.name

Now when the text fills the available horizontal space the text field grows to allow room for an extra line. When the text field fills the available vertical space it scrolls the text input vertically.

Line Limits

The lineLimit modifier, allows you to control the number of lines the text field shows. For example, to show up to four lines before scrolling:

TextField("email", text: $email, axis: .vertical)
.lineLimit(4)

The text field starts showing a single line, but will expand up to four lines before scrolling. Adding the reservesSpace parameter fixes the visible size of the text field to always show that number of lines. For example, to make the text field always show four lines:

TextField("email", text: $email, axis: .vertical)
  .lineLimit(4, reservesSpace: true)

Four line text field with email address wrapped over first two lines. Email is keith.harrison@a.very.long.domain.name

Finally, you can use a range to set the minimum and maximum number of lines. For example, to always show at least two lines and expand up to a maximum of four lines before scrolling:

TextField("email", text: $email, axis: .vertical)
  .lineLimit(2...4)

This starts with two lines:

A two line text field showing placeholder text for email

Then as the text input grows in length the space expands to a maximum of four lines before scrolling vertically:

Four line text field full of text so that first line is scrolling out of view at the top