Menu

A temporary list of choices or actions that opens from a button or a field.

When to use

Use a dropdown menu for actions related to an element, an exposed dropdown to choose a value in a form, and the grouped expressive menu when actions belong to distinct sections.

Menus close when an item is chosen, when the user clicks outside or presses Escape.

Playground

The interactive page has a playground with live property controls for this component and generated code.

Examples

Standard

var expanded by remember { mutableStateOf(false) }

Box(Modifier.fillMaxWidth().height(220.dp), contentAlignment = Alignment.TopStart) {
    IconButton(onClick = { expanded = true }) {
        Icon(Icons.Rounded.MoreVert, contentDescription = "More options")
    }
    DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
        DropdownMenuItem(
            text = { Text("Edit") },
            onClick = { expanded = false },
            leadingIcon = { Icon(Icons.Rounded.Edit, contentDescription = null) },
        )
        DropdownMenuItem(
            text = { Text("Delete") },
            onClick = { expanded = false },
            leadingIcon = { Icon(Icons.Rounded.Delete, contentDescription = null) },
        )
    }
}

Grouped, expressive

Items in separate rounded groups.

var expanded by remember { mutableStateOf(false) }

Box(Modifier.fillMaxWidth().height(300.dp), contentAlignment = Alignment.TopStart) {
    IconButton(onClick = { expanded = true }) {
        Icon(Icons.Rounded.MoreVert, contentDescription = "More options")
    }
    DropdownMenuPopup(expanded = expanded, onDismissRequest = { expanded = false }) {
        val groups = listOf(
            listOf("Edit" to Icons.Rounded.Edit, "Copy" to Icons.Rounded.ContentCopy),
            listOf("Share" to Icons.Rounded.Share, "Delete" to Icons.Rounded.Delete),
        )
        groups.forEachIndexed { groupIndex, items ->
            DropdownMenuGroup(shapes = MenuDefaults.groupShape(groupIndex, groups.size)) {
                items.forEachIndexed { itemIndex, (label, icon) ->
                    DropdownMenuItem(
                        text = { Text(label) },
                        onClick = { expanded = false },
                        shape = MenuDefaults.itemShape(itemIndex, items.size).shape,
                        leadingIcon = { Icon(icon, contentDescription = null) },
                    )
                }
            }
        }
    }
}

Select

An exposed dropdown inside a text field.

val options = listOf("Light", "Dark", "System default")
var expanded by remember { mutableStateOf(false) }
var selected by rememberSaveable { mutableStateOf(options.last()) }

ExposedDropdownMenuBox(
    expanded = expanded,
    onExpandedChange = { expanded = it },
    modifier = Modifier.widthIn(max = 320.dp),
) {
    OutlinedTextField(
        value = selected,
        onValueChange = {},
        readOnly = true,
        label = { Text("Theme") },
        trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
        modifier = Modifier.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable),
    )
    ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
        options.forEach { option ->
            DropdownMenuItem(
                text = { Text(option) },
                onClick = {
                    selected = option
                    expanded = false
                },
            )
        }
    }
}

Parameters

NameTypeDefaultDescription
expandedBooleanWhether the menu is showing.
onDismissRequest() -> UnitCalled on outside click or Escape.
offsetDpOffsetDpOffset(0.dp, 0.dp)Moves the popup relative to its anchor.
DropdownMenuItem.leadingIcon@Composable (() -> Unit)?nullIcon before the text.

Guidelines

Do:

Don't:

Accessibility

Related components