--- title: TriStateCheckbox description: 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. --- {{unstyled_demo:tristatecheckbox}} ## 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. ```kotlin 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. ```kotlin 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](https://composeicons.com).