Composable Component

ListItem

Lists are continuous, vertical indexes of text or images.

ListItem social preview

ClickableListItemSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ClickableListItemSample() {
    Column {
        HorizontalDivider()
        repeat(3) { idx ->
            var count by rememberSaveable { mutableIntStateOf(0) }
            ListItem(
                onClick = { count++ },
                leadingContent = { Icon(Icons.Default.Home, contentDescription = null) },
                trailingContent = { Text("$count") },
                supportingContent = { Text("Additional info") },
                content = { Text("Item ${idx + 1}") },
            )
            HorizontalDivider()
        }
    }
}

ClickableListItemWithClickableChildSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ClickableListItemWithClickableChildSample() {
    Column {
        HorizontalDivider()
        repeat(3) { idx ->
            ListItem(
                onClick = { /* ListItem onClick callback */ },
                leadingContent = { Icon(Icons.Default.Home, contentDescription = null) },
                trailingContent = {
                    IconButton(onClick = { /* Child onClick callback */ }) {
                        Icon(Icons.Default.Favorite, contentDescription = "Localized description")
                    }
                },
                supportingContent = { Text("The trailing icon has a separate click action") },
                content = { Text("Item ${idx + 1}") },
            )
            HorizontalDivider()
        }
    }
}

ListItemWithModeChangeOnLongClickSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ListItemWithModeChangeOnLongClickSample() {
    Column {
        HorizontalDivider()
        var inClickMode by rememberSaveable { mutableStateOf(true) }
        val counts = rememberSaveable { mutableStateListOf(0, 0, 0) }
        val checked = rememberSaveable { mutableStateListOf(false, false, false) }
        repeat(3) { idx ->
            if (inClickMode) {
                ListItem(
                    onClick = { counts[idx]++ },
                    onLongClick = {
                        checked[idx] = true
                        inClickMode = false
                    },
                    leadingContent = { Icon(Icons.Default.Home, contentDescription = null) },
                    trailingContent = { Text("${counts[idx]}") },
                    supportingContent = { Text("Long-click to change interaction mode.") },
                    content = { Text("Item ${idx + 1}") },
                )
            } else {
                ListItem(
                    checked = checked[idx],
                    onCheckedChange = { checked[idx] = it },
                    onLongClick = {
                        inClickMode = true
                        checked.clear()
                        checked.addAll(listOf(false, false, false))
                    },
                    leadingContent = { Checkbox(checked = checked[idx], onCheckedChange = null) },
                    trailingContent = { Icon(Icons.Default.Favorite, contentDescription = null) },
                    supportingContent = { Text("Long-click to change interaction mode.") },
                    content = { Text("Item ${idx + 1}") },
                )
            }
            HorizontalDivider()
        }
    }
}

MultiSelectionListItemSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun MultiSelectionListItemSample() {
    Column {
        HorizontalDivider()
        repeat(3) { idx ->
            var checked by rememberSaveable { mutableStateOf(false) }
            ListItem(
                checked = checked,
                onCheckedChange = { checked = it },
                leadingContent = { Checkbox(checked = checked, onCheckedChange = null) },
                trailingContent = { Icon(Icons.Default.Favorite, contentDescription = null) },
                supportingContent = { Text("Additional info") },
                content = { Text("Item ${idx + 1}") },
            )
            HorizontalDivider()
        }
    }
}

OneLineListItem

@Preview
@Composable
fun OneLineListItem() {
    Column {
        HorizontalDivider()
        ListItem(
            headlineContent = { Text("One line list item with 24x24 icon") },
            leadingContent = {
                Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
            },
        )
        HorizontalDivider()
    }
}

SingleSelectionListItemSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun SingleSelectionListItemSample() {
    Column(Modifier.selectableGroup()) {
        HorizontalDivider()
        var selectedIndex: Int? by rememberSaveable { mutableStateOf(null) }
        repeat(3) { idx ->
            val selected = selectedIndex == idx
            ListItem(
                selected = selected,
                onClick = { selectedIndex = if (selected) null else idx },
                leadingContent = { RadioButton(selected = selected, onClick = null) },
                trailingContent = { Icon(Icons.Default.Favorite, contentDescription = null) },
                supportingContent = { Text("Additional info") },
                content = { Text("Item ${idx + 1}") },
            )
            HorizontalDivider()
        }
    }
}

ThreeLineListItemWithExtendedSupporting

@Preview
@Composable
fun ThreeLineListItemWithExtendedSupporting() {
    Column {
        HorizontalDivider()
        ListItem(
            headlineContent = { Text("Three line list item") },
            supportingContent = { Text("Secondary text that\nspans multiple lines") },
            leadingContent = {
                Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
            },
            trailingContent = { Text("meta") },
        )
        HorizontalDivider()
    }
}

ThreeLineListItemWithOverlineAndSupporting

@Preview
@Composable
fun ThreeLineListItemWithOverlineAndSupporting() {
    Column {
        HorizontalDivider()
        ListItem(
            headlineContent = { Text("Three line list item") },
            overlineContent = { Text("OVERLINE") },
            supportingContent = { Text("Secondary text") },
            leadingContent = {
                Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
            },
            trailingContent = { Text("meta") },
        )
        HorizontalDivider()
    }
}

TwoLineListItem

@Preview
@Composable
fun TwoLineListItem() {
    Column {
        HorizontalDivider()
        ListItem(
            headlineContent = { Text("Two line list item with trailing") },
            supportingContent = { Text("Secondary text") },
            trailingContent = { Text("meta") },
            leadingContent = {
                Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
            },
        )
        HorizontalDivider()
    }
}