androidandroid-jetpack-composeandroid-darkmodeandroid-compose-textfield

Jetpack Compose TextField text colour in dark mode


I've been experimenting with Jetpack compose and I've noticed that although the text colour updates correctly for Text when you switch to dark mode, the text colour for TextField or OutlinedTextField remains stubbornly black. The labels and hint are correctly coloured though.

Having determined that the default text style for the fields is MaterialTheme.typography.body1 I have updated my app theme to include this workaround:

val typography = if (darkTheme) {
    //TODO: Hack to show text field text in dark mode
    MaterialTheme.typography.copy(body1 = MaterialTheme.typography.body1.copy(color = Color.White))
} else {
    MaterialTheme.typography
}
MaterialTheme(colors = colors, content = content, typography = typography)

But if that is the solution I would have to do that for every typography style and it feels like something that should be automatic. So am I doing something wrong, or is this one of those kinks that will be ironed out before it is officially released?

Here is one of my actual Composables (wrapped in my Theme):

@Composable
fun UsernameField(
    value: String,
    isError: Boolean,
    onValueChange: (String) -> Unit,
) {
    Column {
        OutlinedTextField(
            value = value,
            onValueChange = onValueChange,
            modifier = Modifier.fillMaxWidth(),
            label = { Text("Username") },
            isError = isError,
            trailingIcon = {
                ClearIcon(
                    visible = value.isNotEmpty(),
                    onClick = { onValueChange("") }
                )
            }
        )
        Text(
            if (isError) "Minimum 6 characters" else "",
            style = MaterialTheme.typography.caption,
            color = MaterialTheme.colors.error,
            modifier = Modifier.padding(top = 4.dp)
        )
    }
}

@Composable
fun ClearIcon(visible: Boolean, onClick: () -> Unit) {
    if (visible) IconButton(onClick = onClick) {
        Icon(
            imageVector = Icons.Filled.Cancel,
            contentDescription = "Clear username",
        )
    }
}

Solution

  • Try to wrap it with Surface / apply Surface in composable which uses UsernameField. To put it simply, you don't have proper background on which text could take proper color configuration to contrast it.

    There is short example of possible behaviour and fix:

    @Preview
    @Composable
    fun DarkModeTest() {
        MaterialTheme(darkColors()) {
            Column {
                Surface {
                    OutlinedTextField(value = "good", onValueChange = {})
                }
                OutlinedTextField(value = "bad", onValueChange = {})
            }
        }
    }
    

    quick example

    By looking into docs:

    The Surface is responsible for:

    ...

    Content color: Surface uses contentColor to specify a preferred color for the content of this surface - this is used by the Text and Icon components as a default color.