DropdownMenuPopup

A `Popup` that provides the foundation for building a custom menu.

DropdownMenuPopup

Composable Component

A Popup that provides the foundation for building a custom menu.

Common
@ExperimentalMaterial3ExpressiveApi
@Composable
expect fun DropdownMenuPopup(
    expanded: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    offset: DpOffset = DpOffset(0.dp, 0.dp),
    properties: PopupProperties = DefaultMenuProperties,
    content: @Composable ColumnScope.() -> Unit,
)

Parameters

expandedwhether the menu is expanded or not.
onDismissRequestcalled when the user requests to dismiss the menu, such as by tapping outside the menu's bounds.
modifierModifier to be applied to the menu's content.
offsetDpOffset from the original position of the menu.
propertiesPopupProperties for further customization of this popup's behavior.
contentthe content of this dropdown menu.
Android
@ExperimentalMaterial3ExpressiveApi
@Composable
actual fun DropdownMenuPopup(
    expanded: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier,
    offset: DpOffset,
    properties: PopupProperties,
    content: @Composable ColumnScope.() -> Unit,
)

Code Examples

GroupedMenuSample

@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun GroupedMenuSample() {
    val groupInteractionSource = remember { MutableInteractionSource() }
    var expanded by remember { mutableStateOf(false) }
    var homeChecked by remember { mutableStateOf(false) }
    val groupLabels = listOf("Modification", "Navigation")
    val groupItemLabels = listOf(listOf("Edit", "Settings"), listOf("Home", "More Options"))
    val groupItemLeadingIcons =
        listOf(
            listOf(Icons.Outlined.Edit, Icons.Outlined.Settings),
            listOf(null, Icons.Outlined.Info),
        )
    val groupItemCheckedLeadingIcons =
        listOf(
            listOf(Icons.Filled.Edit, Icons.Filled.Settings),
            listOf(Icons.Filled.Check, Icons.Filled.Info),
        )
    val groupItemTrailingIcons: List<List<ImageVector?>> =
        listOf(
            listOf(null, null),
            listOf(
                if (homeChecked) {
                    Icons.Filled.Home
                } else {
                    Icons.Outlined.Home
                },
                Icons.Filled.MoreVert,
            ),
        )
    val groupItemSupportingText: List<List<String?>> =
        listOf(listOf("Edit mode", null), listOf(null, "Opens menu"))
    val checked = remember {
        listOf(mutableStateListOf(false, false), mutableStateListOf(false, false))
    }
    Box(modifier = Modifier.fillMaxSize().wrapContentSize(Alignment.TopStart)) {
        // Icon button should have a tooltip associated with it for a11y.
        TooltipBox(
            positionProvider =
                TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
            tooltip = { PlainTooltip { Text("Localized description") } },
            state = rememberTooltipState(),
        ) {
            IconButton(onClick = { expanded = true }) {
                Icon(Icons.Default.MoreVert, contentDescription = "Localized description")
            }
        }
        DropdownMenuPopup(expanded = expanded, onDismissRequest = { expanded = false }) {
            val groupCount = groupLabels.size
            groupLabels.fastForEachIndexed { groupIndex, label ->
                DropdownMenuGroup(
                    shapes = MenuDefaults.groupShape(groupIndex, groupCount),
                    interactionSource = groupInteractionSource,
                ) {
                    MenuDefaults.Label { Text(label) }
                    HorizontalDivider(
                        modifier =
                            Modifier.padding(horizontal = MenuDefaults.HorizontalDividerPadding)
                    )
                    val groupItemCount = groupItemLabels[groupIndex].size
                    groupItemLabels[groupIndex].fastForEachIndexed { itemIndex, itemLabel ->
                        DropdownMenuItem(
                            text = {
                                val itemSupportingText =
                                    groupItemSupportingText[groupIndex][itemIndex]
                                if (itemSupportingText != null) {
                                    MenuDefaults.LabelWithSupportingText(
                                        supportingText = { Text(itemSupportingText) }
                                    ) {
                                        Text(itemLabel)
                                    }
                                } else {
                                    Text(itemLabel)
                                }
                            },
                            shapes = MenuDefaults.itemShape(itemIndex, groupItemCount),
                            leadingIcon =
                                groupItemLeadingIcons[groupIndex][itemIndex]?.let { iconData ->
                                    { Icon(iconData, contentDescription = null) }
                                },
                            checkedLeadingIcon = {
                                Icon(
                                    groupItemCheckedLeadingIcons[groupIndex][itemIndex],
                                    contentDescription = null,
                                )
                            },
                            trailingIcon =
                                groupItemTrailingIcons[groupIndex][itemIndex]?.let { iconData ->
                                    { Icon(iconData, contentDescription = null) }
                                },
                            checked = checked[groupIndex][itemIndex],
                            onCheckedChange = { checked[groupIndex][itemIndex] = it },
                        )
                    }
                }
                if (groupIndex != groupCount - 1) {
                    Spacer(Modifier.height(MenuDefaults.GroupSpacing))
                }
            }
            if (checked.last().last()) {
                DropdownMenuButtonGroup()
            }
        }
    }
}

Create your own Component Library

Material Components are meant to be used as is and they do not allow customizations. To build your own Jetpack Compose component library use Compose Unstyled