
In this article, we’ll learn how to implement custom text fields using BasicTextField API in Jetpack Compose.
Prerequisites:
This article talks about the Material 2 BasicTextField. If you want the latest Material 3 version, follow this link.
What is BasicTextField in Jetpack Compose?
BasicTextField helps us to create a fully customized input field. Unlike, TextFiled, it has no decorations. If you want to create an input field without following material guidelines, basic text field is the right choice for you.
The API looks like this:
@Composable
fun BasicTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = TextStyle.Default,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
visualTransformation: VisualTransformation = VisualTransformation.None,
onTextLayout: (TextLayoutResult) -> Unit = {},
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
cursorBrush: Brush = SolidColor(Color.Black),
decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
@Composable { innerTextField -> innerTextField() }
)
Most of the parameters are similar to TextFiled. So, before continuing, I highly suggest you read the TextFiled article.
For this article, create an empty Jetpack Compose project and open MainActivity. Next, create a MyUI() composable and call it from the onCreate() method. We will write our code in it.
// we need the following packages
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme(darkTheme = false) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
}
@Composable
private fun MyUI() {
}
Basic Text Field Example:
The value and onValueChange parameters are mandatory for the proper functioning of the basic text field.
@Composable
private fun MyUI() {
var value by remember {
mutableStateOf("")
}
BasicTextField(
value = value,
onValueChange = { newText ->
value = newText
}
)
}
Output:

It is just a plain text field without any customization. Let’s add colors to it.
BasicTextField Text Color:
We can customize the text using the textStyle parameter.
@Composable
private fun MyUI() {
var value by remember {
mutableStateOf("")
}
BasicTextField(
value = value,
onValueChange = { newText ->
value = newText
},
textStyle = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Medium,
color = Color.Red
)
)
}
Output:

Related: How to Use Fonts in Jetpack Compose?
BasicTextField Decoration Box:
The decorationBox parameter helps us to add decorations like rounded corners, background color, hint, placeholder, icons, etc.
@Composable
private fun MyUI() {
var value by remember {
mutableStateOf("")
}
BasicTextField(
value = value,
onValueChange = { newText ->
value = newText
},
textStyle = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Medium,
color = Color.DarkGray
),
decorationBox = { innerTextField ->
Row(
modifier = Modifier
.padding(horizontal = 64.dp) // margin left and right
.fillMaxWidth()
.background(color = Color(0xFFD2F3F2), shape = RoundedCornerShape(size = 16.dp))
.border(
width = 2.dp,
color = Color(0xFFAAE9E6),
shape = RoundedCornerShape(size = 16.dp)
)
.padding(all = 16.dp), // inner padding
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.Search,
contentDescription = "Favorite icon",
tint = Color.DarkGray
)
Spacer(modifier = Modifier.width(width = 8.dp))
innerTextField()
}
}
)
}
Output:

The innerTextField() in the decorationBox is mandatory. It is used to control the placement of the text field. You should call it only once.
Related: Icons in Jetpack Compose
BasicTextField Cursor Color:
Using cursorBrush, we can change the cursor color.
@Composable
private fun MyUI() {
var value by remember {
mutableStateOf("")
}
BasicTextField(
value = value,
onValueChange = { newText ->
value = newText
},
textStyle = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Medium,
color = Color.DarkGray
),
cursorBrush = Brush.verticalGradient(colors = listOf(Color(0xFF2193b0), Color(0xFF6dd5ed)))
)
}
Output:

Related: Gradient Backgrounds in Jetpack Compose
For solid color, call SolidColor() method.
cursorBrush = SolidColor(Color.Green)
Output:

BasicTextField Placeholder:
A placeholder is an optional text that is displayed when the text field is in focus and the input text is empty.
@Composable
private fun MyUI(placeholder: String = "Enter Your Name") {
var value by remember {
mutableStateOf("")
}
BasicTextField(
value = value,
onValueChange = { newText ->
value = newText
},
textStyle = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Medium,
color = Color.DarkGray
),
decorationBox = { innerTextField ->
Box(
modifier = Modifier
.padding(horizontal = 64.dp) // margin left and right
.fillMaxWidth()
.border(
width = 2.dp,
color = Color(0xFFAAE9E6),
shape = RoundedCornerShape(size = 16.dp)
)
.padding(horizontal = 16.dp, vertical = 12.dp), // inner padding
) {
if (value.isEmpty()) {
Text(
text = placeholder,
fontSize = 18.sp,
fontWeight = FontWeight.Normal,
color = Color.LightGray
)
}
innerTextField()
}
}
)
}
Output:

For other parameters, please refer to the TextField article. They work the same in both APIs.
This is all about BasicTextField in Android Jetpack Compose. I hope you learned something new. If you have any doubts, comment below.
Related:
- AnimatedVisibility API in Jetpack Compose
- How to Check Network Connection Programmatically in Android?
- Awesome Navigation Drawer in Jetpack Compose
- Android AppLovin MAX Integration Guide
References: