
In this article, we’ll learn how to implement Checkbox and TriStateCheckbox APIs in Jetpack Compose.
Prerequisites:
What is Checkbox in Android Jetpack Compose?
A checkbox is used to select an item. Checkboxes can turn an option on or off.
Example:

Let’s see how to implement it in the Android Studio.
First, create an empty Compose project and open MainActivity. Create a MyUI() composable and call it from the onCreate() method. We’ll write our code in it.
MainActivity for Material 3 Jetpack Compose:
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TriStateCheckbox
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.state.ToggleableState
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 {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
}
@Composable
private fun MyUI() {
}
MainActivity for the Material 2 version:
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.state.ToggleableState
import androidx.compose.ui.unit.dp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
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() {
}
Note: I’m using Material 3 Jetpack Compose. If you are working with Material 2, you may see slightly different appearance, but the code will still work as expected.
Jetpack Compose provides Checkbox API. It looks like this:
@Composable
fun Checkbox(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
colors: CheckboxColors = CheckboxDefaults.colors()
)
checked – If the checkbox is checked or not.
onCheckedChange – A lambda that is called when the checkbox is clicked. It contains a boolean value that shows if the component is checked or not.
modifier – To modify the layout of the checkbox.
enabled – If the user can interact with the checkbox. If it is false, the component is grayed out.
interactionSource – We can observe and customize the interactions. For example, we can disable the ripple effect.
colors – We can customize the checkbox colors (like checked and unchecked colors).
Simple Checkbox example:
For the proper functioning of the checkbox, checked and onCheckedChange parameters are mandatory.
@Composable
private fun MyUI() {
val contextForToast = LocalContext.current.applicationContext
var checked by remember {
mutableStateOf(true)
}
Checkbox(
checked = checked,
onCheckedChange = { checked_ ->
checked = checked_
Toast.makeText(contextForToast, "checked_ = $checked_", Toast.LENGTH_SHORT).show()
}
)
}
Output:

Checkbox with Text/Label:
There is no parameter to add text to the checkbox. We can put the Text() and Checkbox() composables in a Row layout.
@Composable
private fun MyUI() {
val contextForToast = LocalContext.current.applicationContext
var checked by remember {
mutableStateOf(true)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = checked,
onCheckedChange = { checked_ ->
checked = checked_
Toast.makeText(contextForToast, "checked_ = $checked_", Toast.LENGTH_SHORT).show()
}
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = "Cheese"
)
}
}
Output:

Related: 5 Simple Text Animations in Jetpack Compose
Checkbox Colors:
CheckboxDefaults.colors() method helps us to change the checkbox colors.
@Composable
public final fun colors(
checkedColor: Color,
uncheckedColor: Color,
checkmarkColor: Color,
disabledCheckedColor: Color,
disabledUncheckedColor: Color,
disabledIndeterminateColor: Color
): CheckboxColors
Example:
@Composable
private fun MyUI() {
val contextForToast = LocalContext.current.applicationContext
var checked by remember {
mutableStateOf(true)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = checked,
onCheckedChange = { checked_ ->
checked = checked_
Toast.makeText(contextForToast, "checked_ = $checked_", Toast.LENGTH_SHORT).show()
},
colors = CheckboxDefaults.colors(
checkedColor = Color.Green
)
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = "Cheese"
)
}
}
Output:

Related: Colors, Fonts, and Shapes in Jetpack Compose
Checkbox Size:
To change the checkbox size, use the Modifier‘s scale() method.
@Composable
private fun MyUI() {
val contextForToast = LocalContext.current.applicationContext
var checked by remember {
mutableStateOf(true)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
modifier = Modifier.scale(scale = 1.6f),
checked = checked,
onCheckedChange = { checked_ ->
checked = checked_
Toast.makeText(contextForToast, "checked_ = $checked_", Toast.LENGTH_SHORT).show()
}
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = "Cheese"
)
}
}
Output:

List of Checkboxes or Checkbox Group:
If you have a list of checkboxes, create them using the Checkbox() composable and place them inside a Column layout.
private val fruitsList: List<String> = listOf("Apple", "Mangoes", "Melons")
@Composable
private fun MyUI() {
val contextForToast = LocalContext.current.applicationContext
Column(horizontalAlignment = Alignment.Start) {
fruitsList.forEach { fruitName ->
var checked by remember {
mutableStateOf(true)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = checked,
onCheckedChange = { checked_ ->
checked = checked_
Toast.makeText(contextForToast, "$fruitName $checked_", Toast.LENGTH_SHORT)
.show()
}
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = fruitName
)
}
}
}
}
Output:

Tri-state Checkbox in Jetpack Compose:
There is another checkbox with 3 states. It is called the TriStateCheckbox.
Example:

In the above image, “Operating Systems” is the tri-state checkbox, and Ubuntu, Windows, and Mac are its children (normal checkboxes).
The 3 states are:
ToggleableState.On – In this state, all the children are checked.
ToggleableState.Off – All the children are unchecked.
ToggleableState.Indeterminate – If some, but not all, child checkboxes are checked.
The TriStateCheckbox API is similar to the normal checkbox.
@Composable
fun TriStateCheckbox(
state: ToggleableState,
onClick: (() -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: CheckboxColors = CheckboxDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
)
Example:
@Composable
private fun MyUI() {
// child checkbox states
var checkBox1State by remember {
mutableStateOf(true)
}
var checkBox2State by remember {
mutableStateOf(true)
}
var checkBox3State by remember {
mutableStateOf(true)
}
// parent (tri-state) checkbox state
// it is changed whenever its children's state is changed
val parentCheckBoxState = remember(checkBox1State, checkBox2State, checkBox3State) {
if (checkBox1State && checkBox2State && checkBox3State) ToggleableState.On // if all the children are checked
else if (!checkBox1State && !checkBox2State && !checkBox3State) ToggleableState.Off // if all the children are unchecked
else ToggleableState.Indeterminate // some of the children are checked, others unchecked
}
Column(horizontalAlignment = Alignment.Start) {
Row(verticalAlignment = Alignment.CenterVertically) {
// parent checkbox
TriStateCheckbox(
state = parentCheckBoxState,
onClick = {
// click event on the parent checkbox.
// if the parent checkbox is checked (ToggleableState.On), make all the children unchecked
// else, make them checked
val state = !(parentCheckBoxState == ToggleableState.On)
checkBox1State = state
checkBox2State = state
checkBox3State = state
}
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = "Operating Systems"
)
}
// child checkboxes
CheckBoxItem(
checked = checkBox1State,
osName = "Ubuntu",
onCheckedChange = { checkBox1State = it }
)
CheckBoxItem(
checked = checkBox2State,
osName = "Windows",
onCheckedChange = { checkBox2State = it }
)
CheckBoxItem(
checked = checkBox3State,
osName = "Mac",
onCheckedChange = { checkBox3State = it }
)
}
}
@Composable
private fun CheckBoxItem(
checked: Boolean,
osName: String,
contextForToast: Context = LocalContext.current.applicationContext,
onCheckedChange: (Boolean) -> Unit,
) {
Row(
modifier = Modifier.padding(start = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = checked,
onCheckedChange = { checked_ ->
onCheckedChange(checked_)
Toast.makeText(contextForToast, "$osName $checked_", Toast.LENGTH_SHORT)
.show()
}
)
Text(
modifier = Modifier.padding(start = 2.dp),
text = osName
)
}
}
Output:

Custom Checkbox in Jetpack Compose:
The Checkbox API doesn’t offer many customizations. But, we can easily create a custom checkbox using the Box API. Let’s make a rounded corner checkbox.
@Composable
private fun MyUI(shape: Shape = RoundedCornerShape(size = 6.dp)) {
val contextForToast = LocalContext.current.applicationContext
var checked by remember {
mutableStateOf(true)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Box(
modifier = Modifier
.size(size = 28.dp)
.clip(shape = shape) // to remove the ripple effect on the corners
.clickable {
checked = !checked
Toast
.makeText(contextForToast, "checked = $checked", Toast.LENGTH_SHORT)
.show()
}
.background(
color = if (checked) Color.Magenta else Color.White,
shape = shape
)
.border(
width = 2.dp,
color = if (checked) Color.Magenta else Color.Gray,
shape = shape
),
contentAlignment = Alignment.Center
) {
if (checked) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
tint = Color.White
)
}
}
Text(
modifier = Modifier.padding(start = 6.dp),
text = "Cheese",
fontSize = 20.sp
)
}
}
Output:

Related: Shape APIs (with Examples)
This is all about checkbox APIs in Android Jetpack Compose. I hope you have learned something new. If you have any doubts, comment below.
For more information, look at the Android and Material docs.
Related Articles: