0

I'm building a screen in Jetpack Compose where I want a BasicTextField to be "active" as soon as the screen loads. By "active," I mean that the label should animate upward (just like it does when the field is focused) and the placeholder should be visible. However, I do not want the blinking cursor to appear until the user actually interacts with the BasicTextField.

Currently, my implementation auto-focuses the BasicTextField on launch using a FocusRequester, but this approach also brings up the cursor immediately, which is not the desired behavior.

Here’s a simplified version of my current code:

MainActivity.kt

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            val stateOne = rememberTextFieldState(initialText = "Hellow")
            val stateTwo = rememberTextFieldState()
            BasicTextFieldExamples(
                stateOne,
                remember { MutableInteractionSource() },
                stateTwo,
                remember { MutableInteractionSource() },
            )
        }
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun BasicTextFieldExamples(
        stateOne: TextFieldState,
        firstInteractionSource: MutableInteractionSource,
        stateOTwo: TextFieldState,
        secondInteractionSource: MutableInteractionSource,
    ) {
        Column(
            Modifier
                .fillMaxSize()
                .padding(50.dp)
        ) {
            BasicTextField(
                state = stateOne,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                readOnly = true,
                interactionSource = firstInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOne,
                    enabled = true,
                    label = {
                        Text("First Name")
                    },
                    placeholder = {
                        Text("Example 1")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = firstInteractionSource,
                    outputTransformation = null
                )
            )
            BasicTextField(
                state = stateOTwo,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                interactionSource = secondInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOTwo,
                    enabled = true,
                    label = {
                        Text("Last Name")
                    },
                    placeholder = {
                        Text("Example 2")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = secondInteractionSource,
                    outputTransformation = null
                )
            )
        }
    }
}
7
  • Clone TextField() and implement what you want. Commented Feb 5 at 18:37
  • Sorry @CommonsWare I don't know how to implement like that in TextField. Commented Feb 5 at 19:07
  • I do not know if you are using Compose Material or Compose Material3. At least with Compose Material, it looks like you would need to create a modified version of TextFieldDefaults.TextFieldDecorationBox() and use that for the decorationBox. That, in turn, is based on CommonDecorationBox(), and you would need to change the placeholder behavior. Commented Feb 5 at 19:15
  • I updated my code and I'm using material 3. Commented Feb 5 at 20:47
  • Here is TextField() for Material3. The placeholder and label are controlled by TextFieldDefaults.decorator(). Commented Feb 5 at 20:55

1 Answer 1

1

I think this might be what you need, using TextField rather than BasicTextField. You can customize the cursor colors via the provided TextFieldColors, so you can separately maintain a state that decides whether to show or hide the cursor, and hide it by setting the colors to transparent.

val focusRequester = remember { FocusRequester() }
LaunchedEffect("focus") { focusRequester.requestFocus() }

var showCursor by remember { mutableStateOf(false) }
val colors =
    if (showCursor) {
      TextFieldDefaults.colors()
    } else {
      TextFieldDefaults.colors()
          .copy(cursorColor = Color.Transparent, errorCursorColor = Color.Transparent)
    }

var text by remember { mutableStateOf("") }
TextField(
    value = text,
    colors = colors,
    onValueChange = { text = it },
    label = { Text(text = "Label") },
    placeholder = { Text(text = "Placeholder") },
    modifier =
        Modifier.focusRequester(focusRequester).pointerInput("key") {
          awaitPointerEventScope {
            awaitFirstDown(requireUnconsumed = false)
            showCursor = true
          }
        })
Sign up to request clarification or add additional context in comments.

2 Comments

It's nice trick but it will open the keyboard if we put the focus in the keyboard.
Additional this solution only works on single TextField but if we have multiple textfield then I need to use multiple FocusRequester.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.