9

In material design TextField page TextField has properties such as

enter image description here

Assistive elements provide additional detail about text entered into text fields.

  1. Helper text Helper text conveys additional guidance about the input field, such as how it will be used. It should only take up a single line, being persistently visible or visible only on focus.

  2. Error message When text input isn't accepted, an error message can display instructions on how to fix it. Error messages are displayed below the input line, replacing helper text until fixed.

  3. Icons Icons can be used to message alerts as well. Pair them with error messages to provide redundant alerts, which are useful when you need to design for colorblind users.

  4. Character counter Character or word counters should be used if there is a character or word limit. They display the ratio of characters used and the total character limit.

Do these properties exist for Jetpack Compose TextField as of compose 1.0.0-alpha09?

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • 1
    According to the issue tracker it looks like this one is in-flight. https://issuetracker.google.com/issues/182142737 – Victor Ude Mar 16 '21 at 19:29
  • 1
    The above issue has been resolved as of beta06, however it does not introduce any of the OP's missing properties. – Tom May 17 '21 at 01:22
  • according to this change (https://android-review.googlesource.com/c/platform/frameworks/support/+/1651127/9/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt#139), just add `isError` prop to your text field. Yet, no idea how word/char counter implemented. – Mirjalal Jun 11 '21 at 19:17

2 Answers2

5

With M3 you can use the the supportingText attribute that is the optional supporting text to be displayed below the text field.

For characters count you have to applied textAlign = TextAlign.End:

val maxChar = 5

TextField(
    value = text,
    onValueChange = {
        if (it.length <= maxChar) text = it
    },
    modifier = Modifier.fillMaxWidth(),
    supportingText = {
        Text(
            text = "${text.length} / $maxChar",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.End,
        )
    },
)

enter image description here

The same attribute can be used for helper text and message errors:

val errorMessage = "Text input too long"
var text by rememberSaveable { mutableStateOf("") }
var isError by rememberSaveable { mutableStateOf(false) }
val charLimit = 10

fun validate(text: String) {
    isError = text.length > charLimit
}

TextField(
    value = text,
    onValueChange = {
        text = it
        validate(text)
    },
    singleLine = true,
    isError = isError,
    supportingText = {
        if (isError) {
            Text(
                modifier = Modifier.fillMaxWidth(),
                text = "Limit: ${text.length}/$charLimit",
                color = MaterialTheme.colorScheme.error
            )
        }
    },
    trailingIcon = {
        if (isError)
                Icon(Icons.Filled.Error,"error", tint = MaterialTheme.colorScheme.error)
     }
)

enter image description here


With M2 there aren't built-in properties to display an error message or the counter text.
However you can use a custom composable.

For the error message you can use something like:

var text by rememberSaveable { mutableStateOf("") }
var isError by rememberSaveable { mutableStateOf(false) }

fun validate(text: String) {
    isError = /* .... */
}

Column {
    TextField(
        value = text,
        onValueChange = {
            text = it
            isError = false
        },
        trailingIcon = {
            if (isError)
            Icon(Icons.Filled.Error,"error", tint = MaterialTheme.colors.error)
        },
        singleLine = true,
        isError = isError,
        keyboardActions = KeyboardActions { validate(text) },
    )
    if (isError) {
        Text(
            text = "Error message",
            color = MaterialTheme.colors.error,
            style = MaterialTheme.typography.caption,
            modifier = Modifier.padding(start = 16.dp)
        )
    }
}

enter image description here

To display the counter text you can use something like:

val maxChar = 5
Column(){
    TextField(
        value = text,
        onValueChange = {
            if (it.length <= maxChar) text = it
        },
        modifier = Modifier.fillMaxWidth()
    )
    Text(
        text = "${text.length} / $maxChar",
        textAlign = TextAlign.End,
        style = MaterialTheme.typography.caption,
        modifier = Modifier.fillMaxWidth().padding(end = 16.dp)
    )
}

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • Jeez. Bring back the XML View rendering! All of this to display an error message on a Textfield – Val Okafor Nov 27 '21 at 03:40
  • problem with those standalone views is that they get obscured by the keyboard. :/ only the textfield is kept above the keyboard – cwiesner Apr 05 '22 at 13:15
1

trailingIcon for the icon.

For the text at the bottom I just used

Text(
    text = "Error message",
    color = MaterialTheme.colors.error,
    style = MaterialTheme.typography.caption,
    modifier = Modifier.padding(start = 16.dp)
)

Might be included in the future? Weirdly enough the documentation for isError says:

indicates if the text field's current value is in error. If set to true, the label, bottom indicator and trailing icon by default will be displayed in error color

What bottom indicator? There is no such thing. Weird.

Edward van Raak
  • 4,841
  • 3
  • 24
  • 38
  • Bottom indicator is the line under the text field, it gets red as well if `isError` is set. – wujek Aug 12 '21 at 09:00