Compose Unstyled 2.0 is out! Check the official announcement blog ->

Dropdown Menu

Anchored menus for selections, overflow actions, and contextual commands.

Use dropdown menus for compact action lists that open from a trigger.

View on GitHub
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.composables.icons.lucide.Check
import com.composables.icons.lucide.ChevronsUpDown
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Monitor
import com.composables.icons.lucide.Moon
import com.composables.icons.lucide.Palette
import com.composables.icons.lucide.Sun
import com.composables.ui.components.Button
import com.composables.ui.components.ButtonStyle
import com.composables.ui.components.DropdownMenu
import com.composables.ui.components.DropdownMenuAlignment
import com.composables.ui.components.DropdownMenuItem
import com.composables.ui.components.DropdownMenuPanel
import com.composables.ui.components.Icon
import com.composables.ui.components.Text

@Composable
fun DropdownMenuExample() {
    var expanded by remember { mutableStateOf(false) }
    var selectedColorScheme by remember { mutableStateOf("Light") }

    DropdownMenu(
        expanded = expanded,
        onExpandedChange = { expanded = it },
        alignment = DropdownMenuAlignment.End,
        panel = {
            DropdownMenuPanel {
                DropdownMenuItem(
                    onClick = {
                        selectedColorScheme = "System"
                        expanded = false
                    },
                    leading = {
                        if (selectedColorScheme == "System") {
                            Icon(
                                imageVector = Lucide.Check,
                                contentDescription = null,
                                modifier = Modifier.size(16.dp),
                            )
                        } else {
                            Spacer(Modifier.width(16.dp))
                        }
                    },
                    trailing = {
                        Icon(
                            imageVector = Lucide.Monitor,
                            contentDescription = null,
                            modifier = Modifier.size(16.dp),
                        )
                    },
                ) {
                    Text("System")
                }
                DropdownMenuItem(
                    onClick = {
                        selectedColorScheme = "Dark"
                        expanded = false
                    },
                    leading = {
                        if (selectedColorScheme == "Dark") {
                            Icon(
                                imageVector = Lucide.Check,
                                contentDescription = null,
                                modifier = Modifier.size(16.dp),
                            )
                        } else {
                            Spacer(Modifier.width(16.dp))
                        }
                    },
                    trailing = {
                        Icon(
                            imageVector = Lucide.Moon,
                            contentDescription = null,
                            modifier = Modifier.size(16.dp),
                        )
                    },
                ) {
                    Text("Dark")
                }
                DropdownMenuItem(
                    onClick = {
                        selectedColorScheme = "Light"
                        expanded = false
                    },
                    leading = {
                        if (selectedColorScheme == "Light") {
                            Icon(
                                imageVector = Lucide.Check,
                                contentDescription = null,
                                modifier = Modifier.size(16.dp),
                            )
                        } else {
                            Spacer(Modifier.width(16.dp))
                        }
                    },
                    trailing = {
                        Icon(
                            imageVector = Lucide.Sun,
                            contentDescription = null,
                            modifier = Modifier.size(16.dp),
                        )
                    },
                ) {
                    Text("Light")
                }
            }
        },
    ) {
        Button(
            onClick = { expanded = expanded.not() },
            modifier = Modifier.fillMaxWidth(),
            style = ButtonStyle.Ghost,
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.spacedBy(12.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                Icon(
                    imageVector = Lucide.Palette,
                    contentDescription = null,
                    modifier = Modifier.size(18.dp),
                )
                Text("Color scheme")
                Spacer(Modifier.weight(1f))
                Text(selectedColorScheme)
                Icon(
                    imageVector = Lucide.ChevronsUpDown,
                    contentDescription = null,
                    modifier = Modifier.size(16.dp),
                )
            }
        }
    }
}

Installation

implementation("com.composables:ui:0.1.0")

Examples

Overflow menu

View on GitHub
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.composables.icons.lucide.EllipsisVertical
import com.composables.icons.lucide.Heart
import com.composables.icons.lucide.Link
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Share
import com.composables.icons.lucide.Trash2
import com.composables.ui.components.ButtonStyle
import com.composables.ui.components.DropdownMenu
import com.composables.ui.components.DropdownMenuAlignment
import com.composables.ui.components.DropdownMenuItem
import com.composables.ui.components.DropdownMenuItemStyle
import com.composables.ui.components.DropdownMenuPanel
import com.composables.ui.components.Icon
import com.composables.ui.components.IconButton
import com.composables.ui.components.Text
import com.composables.ui.components.Toolbar

@Composable
fun DropdownMenuToolbarExample() {
    var expanded by remember { mutableStateOf(false) }

    Toolbar(
        modifier = Modifier.fillMaxWidth(),
        title = { Text("Details") },
        trailing = {
            DropdownMenu(
                expanded = expanded,
                onExpandedChange = { expanded = it },
                alignment = DropdownMenuAlignment.End,
                panel = {
                    DropdownMenuPanel {
                        DropdownMenuItem(
                            onClick = { expanded = false },
                            leading = {
                                Icon(
                                    imageVector = Lucide.Share,
                                    contentDescription = null,
                                    modifier = Modifier.size(16.dp),
                                )
                            },
                        ) {
                            Text("Share")
                        }
                        DropdownMenuItem(
                            onClick = { expanded = false },
                            leading = {
                                Icon(
                                    imageVector = Lucide.Heart,
                                    contentDescription = null,
                                    modifier = Modifier.size(16.dp),
                                )
                            },
                        ) {
                            Text("Add to favorites")
                        }
                        DropdownMenuItem(
                            onClick = { expanded = false },
                            leading = {
                                Icon(
                                    imageVector = Lucide.Link,
                                    contentDescription = null,
                                    modifier = Modifier.size(16.dp),
                                )
                            },
                        ) {
                            Text("Copy link")
                        }
                        DropdownMenuItem(
                            onClick = { expanded = false },
                            style = DropdownMenuItemStyle.Destructive,
                            leading = {
                                Icon(
                                    imageVector = Lucide.Trash2,
                                    contentDescription = null,
                                    modifier = Modifier.size(16.dp),
                                )
                            },
                        ) {
                            Text("Delete")
                        }
                    }
                },
            ) {
                IconButton(
                    onClick = { expanded = expanded.not() },
                    style = ButtonStyle.Ghost,
                ) {
                    Icon(
                        imageVector = Lucide.EllipsisVertical,
                        contentDescription = "More options",
                        modifier = Modifier.size(18.dp),
                    )
                }
            }
        },
    )
}

API Reference

An anchored dropdown menu with a trigger and floating panel.

@Composable
fun DropdownMenu(
    expanded: Boolean,
    onExpandedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    side: DropdownMenuSide = DropdownMenuSide.Bottom,
    alignment: DropdownMenuAlignment = DropdownMenuAlignment.Start,
    sideOffset: Dp = 4.dp,
    alignmentOffset: Dp = 0.dp,
    panel: @Composable DropdownMenuScope.() -> Unit,
    anchor: @Composable () -> Unit,
)
Parameter Type Description
expanded Boolean Whether the dropdown menu is currently open.
onExpandedChange (Boolean) -> Unit Called when the dropdown menu should open or close.
modifier Modifier Modifier applied to the component.
side DropdownMenuSide Side of the anchor where the menu panel should appear.
alignment DropdownMenuAlignment Alignment of the menu panel along the chosen side.
sideOffset Dp Distance between the menu panel and its anchor.
alignmentOffset Dp Offset applied along the anchor edge.
panel @Composable DropdownMenuScope.() -> Unit Composable menu panel content displayed by the dropdown.
anchor @Composable () -> Unit Composable anchor that opens the dropdown menu.

A styled dropdown panel surface.

@Composable
fun DropdownMenuScope.DropdownMenuPanel(
    modifier: Modifier = Modifier,
    shape: Shape = Theme[shapes][menuShape],
    backgroundColor: Color = Theme[colors][panelColor],
    contentColor: Color = Theme[colors][onPanelColor],
    shadow: Shadow = Theme[shadows][raisedShadow],
    minWidth: Dp = 160.dp,
    maxWidth: Dp = 320.dp,
    enter: EnterTransition? = null,
    exit: ExitTransition? = null,
    content: @Composable DropdownMenuPanelContentScope.() -> Unit,
)
Parameter Type Description
modifier Modifier Modifier applied to the component.
shape Shape Shape used for the dropdown panel.
backgroundColor Color Background color used for the menu panel.
contentColor Color Color used for menu content.
shadow Shadow Shadow applied to the menu panel.
minWidth Dp Minimum width used for the menu panel.
maxWidth Dp Maximum width used for the menu panel.
enter EnterTransition? Transition used when the menu panel appears.
exit ExitTransition? Transition used when the menu panel disappears.
content @Composable DropdownMenuPanelContentScope.() -> Unit Composable content displayed by the component.

A selectable action inside a dropdown menu.

@Composable
fun DropdownMenuPanelContentScope.DropdownMenuItem(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    closeOnClick: Boolean = true,
    style: DropdownMenuItemStyle = DropdownMenuItemStyle.Default,
    leading: (@Composable () -> Unit)? = null,
    trailing: (@Composable () -> Unit)? = null,
    content: @Composable RowScope.() -> Unit,
)
Parameter Type Description
onClick () -> Unit Called when the menu item is selected.
modifier Modifier Modifier applied to the component.
enabled Boolean Whether the item can be interacted with.
closeOnClick Boolean Whether clicking the item should close the menu.
style DropdownMenuItemStyle Visual style used by the menu item.
leading (@Composable () -> Unit)? Optional leading content shown before the menu item label.
trailing (@Composable () -> Unit)? Optional trailing content shown after the menu item label.
content @Composable RowScope.() -> Unit Composable content displayed by the component.

A non-interactive label row for grouping menu items.

@Composable
fun DropdownMenuPanelContentScope.DropdownMenuLabel(
    modifier: Modifier = Modifier,
    contentColor: Color = Theme[colors][mutedColor],
    content: @Composable RowScope.() -> Unit,
)
Parameter Type Description
modifier Modifier Modifier applied to the component.
contentColor Color Color used for menu content.
content @Composable RowScope.() -> Unit Composable content displayed by the component.

A visual separator between menu groups.

@Composable
fun DropdownMenuPanelContentScope.DropdownMenuSeparator(
    modifier: Modifier = Modifier,
)
Parameter Type Description
modifier Modifier Modifier applied to the component.

Side options for menu placement relative to its anchor.

@JvmInline
value class DropdownMenuSide internal constructor(@Suppress("unused") private val value: Int)
Value Description
Top Places the menu above its anchor.
Bottom Places the menu below its anchor.
Start Places the menu before its anchor in the layout direction.
End Places the menu after its anchor in the layout direction.

Alignment options for menu placement along the anchor edge.

@JvmInline
value class DropdownMenuAlignment internal constructor(@Suppress("unused") private val value: Int)
Value Description
Start Aligns the panel to the start edge of the anchor.
Center Centers the panel against the anchor.
End Aligns the panel to the end edge of the anchor.

Visual style variants for dropdown menu items.

@JvmInline
value class DropdownMenuItemStyle internal constructor(@Suppress("unused") private val value: Int)
Value Description
Default Uses the default menu item colors.
Destructive Uses destructive emphasis for dangerous actions.