Barry Irvine
Barry Irvine

Reputation: 13867

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",
        )
    }
}

Upvotes: 11

Views: 10976

Answers (4)

Arunabh Das
Arunabh Das

Reputation: 14352

Try the below solution

            OutlinedTextField(
            value = state.searchQuery,
            onValueChange = onValueChange,
            modifier = Modifier
                .padding(48.dp)
                .fillMaxWidth(),
            placeholder = {
                Text(
                    text = "Search...",
                    color = Color.White,
                    fontSize = MaterialTheme.typography.titleSmall.fontSize,
                    fontWeight = FontWeight.Bold
                )
            },
            colors = TextFieldDefaults.outlinedTextFieldColors(
                unfocusedLabelColor = MaterialTheme.colorScheme.inversePrimary,
                textColor = Color.White
            ),
            maxLines = 1,
            singleLine = true
        )

Upvotes: -1

Gabriele Mariotti
Gabriele Mariotti

Reputation: 363597

With 1.0.0 the text color of TextField should work without issue in dark mode.

enter image description here

In any case the textColor is currently based on:

textColor: Color = LocalContentColor.current.copy(LocalContentAlpha.current)

You can avoid to change every typography styles using something like:

CompositionLocalProvider(LocalContentColor provides MaterialTheme.colors.secondary) {
    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

enter image description here

Upvotes: 6

ZeD
ZeD

Reputation: 374

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.

Upvotes: 17

droidv
droidv

Reputation: 888

What I have been doing to customize every color on my OutlinedTextField components, is to use the "colors" argument along with the "TextFieldDefaults.outlinedTextFieldColors()" method.

Below is an example:

OutlinedTextField(
    value = text,
    onValueChange = { text = it },
    colors = TextFieldDefaults.outlinedTextFieldColors(
        unfocusedLabelColor = MaterialTheme.colors.primary
    )
)

On "outlinedTextFieldColors", you can define basically all of the colors you need in terms of a TextField state, as shown as below:

Creates a TextFieldColors that represents the default input text, background and content (including label, placeholder, leading and trailing icons) colors used in an OutlinedTextField.

@Composable
fun outlinedTextFieldColors(
    textColor: Color = LocalContentColor.current.copy(LocalContentAlpha.current),
    disabledTextColor: Color = textColor.copy(ContentAlpha.disabled),
    backgroundColor: Color = Color.Transparent,
    cursorColor: Color = MaterialTheme.colors.primary,
    errorCursorColor: Color = MaterialTheme.colors.error,
    focusedBorderColor: Color =
        MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
    unfocusedBorderColor: Color =
        MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
    disabledBorderColor: Color = unfocusedBorderColor.copy(alpha = ContentAlpha.disabled),
    errorBorderColor: Color = MaterialTheme.colors.error,
    leadingIconColor: Color =
        MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
    disabledLeadingIconColor: Color = leadingIconColor.copy(alpha = ContentAlpha.disabled),
    errorLeadingIconColor: Color = leadingIconColor,
    trailingIconColor: Color =
        MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
    disabledTrailingIconColor: Color = trailingIconColor.copy(alpha = ContentAlpha.disabled),
    errorTrailingIconColor: Color = MaterialTheme.colors.error,
    focusedLabelColor: Color =
        MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
    unfocusedLabelColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
    disabledLabelColor: Color = unfocusedLabelColor.copy(ContentAlpha.disabled),
    errorLabelColor: Color = MaterialTheme.colors.error,
    placeholderColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
    disabledPlaceholderColor: Color = placeholderColor.copy(ContentAlpha.disabled)
)

I haven't been having any issue with Dark and Light themes with this implementation.

Upvotes: 3

Related Questions