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
)
)
}
}
}
TextField()and implement what you want.TextFieldDefaults.TextFieldDecorationBox()and use that for thedecorationBox. That, in turn, is based onCommonDecorationBox(), and you would need to change the placeholder behavior.TextField()for Material3. The placeholder and label are controlled byTextFieldDefaults.decorator().