How to show error message in OutlinedTextField in Jetpack Compose
Asked Answered
T

5

42

I need to show error message in OutlinedTextField and I don't find any documentation about how to do it. I found several ways in tutorials, for example to create custom input field with hint or create Text just below input field, but they very old and maybe there is a better way. I need show error message like this:

enter image description here

Code:

@Composable
fun EmailInputField(value: MutableState<String>, state: AuthState) {

    OutlinedTextField(
        value = value.value,
        onValueChange = { value.value = it },
        modifier = Modifier.fillMaxWidth(1f).height(60.dp),
        textStyle = TextStyle(color = Color.White),
        label = { Text(text = "Email", color = Color.White) },
        colors = TextFieldDefaults.outlinedTextFieldColors(
            focusedBorderColor = blue,
            unfocusedBorderColor = Color.White
        ),
        isError = state is AuthState.ValidationError,
        singleLine = true
    )
}
Tie answered 29/7, 2021 at 9:13 Comment(0)
V
77

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

    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)
        },
        keyboardActions = KeyboardActions { validate(text) },
    )

enter image description here


The M2 TextField components doesn't support an errorMessage field.

You can easily achieve it using 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

Violate answered 29/7, 2021 at 11:40 Comment(2)
The issue here is about BringIntoViewRequester. TextField manage its own BringIntoViewRequester, when the position is covered by keyboard, it will bring it self up to prevent covered. Unless we manage the error text focus requester, user can't see it when BringIntoViewRequester of TextField invoked.Course
Unfortunately, there is no Error icon anymore, Icons.Filled.Warning is the closest oneKlemperer
B
12

Update

In Jetpack Compose Material 3 version 1.0.0 (released on October 24, 2022), we can use the supportingText attribute in the OutlinedTextField

Pics from Docs Screenshots

supportingText takes a Composable.


Reference
Compose Material 3 Release Notes

Bascio answered 30/10, 2022 at 12:2 Comment(1)
I'm confused. I see the screenshot, I read the docu but an OutlinedTextField has no parameter "Supporting text" What am I missing?Crabby
W
11

Here is a ready to use composable that you can copy paste into your code. It has a String field called errorthat will display the error whenever it is not empty (that way you only have one state variable to keep track of). It is a bit verbose so you are able to customize it as you would any OutlinedTextField.

enter image description here

sample usage

OutlinedTextFieldValidation(
        value = studentState.firstName.value,
        onValueChange = { onFirstNameChange(it) },
        label = { Text(text = "First name") },
        error = "field cannot be empty"
    )

code to copy:

@Composable
fun OutlinedTextFieldValidation(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier.fillMaxWidth(0.8f),
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    error: String = "",
    isError: Boolean = error.isNotEmpty(),
    trailingIcon: @Composable (() -> Unit)? = {
        if (error.isNotEmpty())
            Icon(Icons.Filled.Error, "error", tint = MaterialTheme.colors.error)
    },
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = MaterialTheme.shapes.small,
    colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors(
        disabledTextColor = Color.Black
    )

) {

    Column(modifier = modifier
        .padding(8.dp)) {
        OutlinedTextField(
            enabled = enabled,
            readOnly = readOnly,
            value = value,
            onValueChange = onValueChange,
            modifier = Modifier
                .fillMaxWidth(),
            singleLine = singleLine,
            textStyle = textStyle,
            label = label,
            placeholder = placeholder,
            leadingIcon = leadingIcon,
            trailingIcon = trailingIcon,
            isError = isError,
            visualTransformation = visualTransformation,
            keyboardOptions = keyboardOptions,
            keyboardActions = keyboardActions,
            maxLines = maxLines,
            interactionSource = interactionSource,
            shape = shape,
            colors = colors
        )
        if (error.isNotEmpty()) {
            Text(
                text = error,
                color = MaterialTheme.colors.error,
                style = MaterialTheme.typography.caption,
                modifier = Modifier.padding(start = 16.dp, top = 0.dp)
            )
        }
    }
}
Whither answered 19/3, 2022 at 19:24 Comment(2)
it is not working in OutlinedTextField. Causing problems like None of the following functions can be called with the arguments supplied. and @Composable invocations can only happen from the context of a @Composable function. How can I resolve this? Please help!!Handling
@gaurav make sure you added the composable fun to your code base and rememver you need to call the OutlinedTextFieldValidation from a function anotated as [@Composable}Whither
T
5

Updated answer for @Gabriele Mariotti's solution that works with latest Compose and Material3:

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.Info, "Error", tint = MaterialTheme.colorScheme.error)
        },
        singleLine = true,
        isError = isError,
        keyboardActions = KeyboardActions { validate(text) },
    )
    if (isError) {
        Text(
            text = "Error message",
            color = MaterialTheme.colorScheme.error,
            style = MaterialTheme.typography.bodySmall,
            modifier = Modifier.padding(start = 16.dp)
        )
    }
}

error sample

Tanh answered 19/6, 2022 at 12:4 Comment(0)
O
1

To resolve None of the following functions can be called with the arguments supplied. and @Composable invocations can only happen from the context of a @Composable function you can do like this:

@Composable
fun MyCustomTextField(
    value: String,
    onValueChange: (String) -> Unit,
    supportingText: String?,
    isError: Boolean
) {
    OutlinedTextField(
        value = value,
        onValueChange = onValueChange,
        supportingText = supportingText?.let {
            @Composable {
                Text(
                    text = supportingText,
                    style = MaterialTheme.typography.bodySmall
                )
            }
        },
        isError = isError
    )
}
Ozonize answered 15/1 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.