TriStateCheckbox
A foundational component for creating three-state checkboxes that can be checked, unchecked, or in an indeterminate state. Perfect for "select all" scenarios and hierarchical selections.
Accessible out of the box and fully renderless, so that you can apply any styling you like.
Basic Example
To create a tri-state checkbox use the TriStateCheckbox
component. The checkbox supports three states: On
, Off
, and Indeterminate
. You can cycle through states by clicking or pressing Enter/Space while focused.
The checkIcon
composable receives the current ToggleableState
and should render the appropriate icon for each state.
var triState by remember { mutableStateOf(ToggleableState.Off) }
TriStateCheckbox(
value = triState,
onClick = {
triState = when (triState) {
ToggleableState.Off -> ToggleableState.On
ToggleableState.On -> ToggleableState.Indeterminate
ToggleableState.Indeterminate -> ToggleableState.Off
}
},
shape = RoundedCornerShape(4.dp),
backgroundColor = Color.White,
borderWidth = 1.dp,
borderColor = Color.Black.copy(0.33f),
modifier = Modifier.size(24.dp)
) { state ->
when (state) {
ToggleableState.On -> Icon(Check, contentDescription = null)
ToggleableState.Indeterminate -> Icon(Minus, contentDescription = null)
ToggleableState.Off -> Unit // No icon shown
}
}
Styling
The TriStateCheckbox is fully renderless and handles all UX logic, accessibility and keyboard interactions for you, but does not display any information on the screen by default.
The shape
of the checkbox is used to clip the checkbox and applies to both the background and border.
The borderColor
and borderWidth
parameters place a border around the checkbox, taking the given shape into consideration.
The backgroundColor
sets the color of the checkbox's surface.
The checkIcon
composable is where you define what gets displayed for each state. It receives the current ToggleableState
as a parameter.
Code Examples
Select All Pattern
A common use case for TriStateCheckbox is implementing "select all" functionality with a group of child checkboxes.
val checkboxOptions = listOf("Option 1", "Option 2", "Option 3")
var selected by remember { mutableStateOf(List(checkboxOptions.size) { false }) }
val triState = when {
selected.all { it } -> ToggleableState.On
selected.none { it } -> ToggleableState.Off
else -> ToggleableState.Indeterminate
}
Column {
// Parent TriState checkbox - "Select All"
Row(verticalAlignment = Alignment.CenterVertically) {
TriStateCheckbox(
value = triState,
onClick = {
val newState = when (triState) {
ToggleableState.Off -> true
ToggleableState.Indeterminate -> true
ToggleableState.On -> false
}
selected = List(checkboxOptions.size) { newState }
},
shape = RoundedCornerShape(4.dp),
backgroundColor = Color.White,
borderWidth = 1.dp,
borderColor = Color.Black.copy(0.33f),
modifier = Modifier.size(24.dp),
contentDescription = "Select all options"
) { state ->
when (state) {
ToggleableState.On -> Icon(Check, contentDescription = null)
ToggleableState.Indeterminate -> Icon(Minus, contentDescription = null)
ToggleableState.Off -> Unit
}
}
Spacer(Modifier.width(12.dp))
Text("Select All")
}
// Child checkboxes
checkboxOptions.forEachIndexed { index, option ->
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = selected[index],
onCheckedChange = { checked ->
selected = selected.toMutableList().apply {
this[index] = checked
}
},
shape = RoundedCornerShape(4.dp),
backgroundColor = Color.White,
borderWidth = 1.dp,
borderColor = Color.Black.copy(0.33f),
modifier = Modifier.size(24.dp),
contentDescription = option
) {
Icon(Check, contentDescription = null)
}
Spacer(Modifier.width(12.dp))
Text(option)
}
}
}
Keyboard Interactions
Key | Description |
---|---|
Enter | Triggers the onClick callback |
Space | Triggers the onClick callback |
Component API
Parameter | Description |
---|---|
value | The current state (ToggleableState.On , ToggleableState.Off , or ToggleableState.Indeterminate ) |
onClick | Callback invoked when the checkbox is clicked |
modifier | Modifier to be applied to the checkbox |
backgroundColor | Background color of the checkbox (defaults to Color.Transparent ) |
contentColor | Color of the content inside the checkbox |
enabled | Whether the checkbox is enabled for interaction (defaults to true ) |
shape | Shape of the checkbox (defaults to RectangleShape ) |
borderColor | Color of the border |
borderWidth | Width of the border (defaults to 1.dp ) |
interactionSource | MutableInteractionSource for handling interactions |
indication | Visual indication for interactions |
contentDescription | Accessibility description of the checkbox |
checkIcon | Composable function that receives the state and renders the appropriate icon |
Icons
You can find the check and minus icons used in our examples and many other icons at composeicons.com.