Skip to content

OverlayCascadingListPopup

OverlayCascadingListPopup is a popup list that supports a two-level cascading menu. Items whose DropdownItem.children is non-empty become submenu triggers; tapping such an item morphs the popup into a secondary list anchored at the trigger row, while the primary list scales down behind a translucent mask. Cascading depth is limited to 2.

Prerequisite

This component depends on Scaffold providing MiuixPopupHost to render popup content. It must be used within Scaffold, otherwise popup content will not render correctly.

Import

kotlin
import top.yukonga.miuix.kmp.overlay.OverlayCascadingListPopup
import top.yukonga.miuix.kmp.basic.DropdownEntry
import top.yukonga.miuix.kmp.basic.DropdownItem

Basic Usage

Build entries so that some DropdownItems carry a non-empty children list. The component renders a chevron next to such trigger rows; tapping the trigger expands the second level inline.

kotlin
var showPopup by remember { mutableStateOf(false) }
var sortIndex by remember { mutableStateOf(0) }
var viewIndex by remember { mutableStateOf(0) }

val sortLabels = listOf("Sort by capture date", "Sort by date added")
val viewLabels = listOf("Group by date", "Compact")
val entries = listOf(
    DropdownEntry(
        items = sortLabels.mapIndexed { idx, label ->
            DropdownItem(
                text = label,
                selected = sortIndex == idx,
                onClick = { sortIndex = idx },
            )
        },
    ),
    DropdownEntry(
        items = listOf(
            DropdownItem(
                text = "View mode",
                children = viewLabels.mapIndexed { idx, label ->
                    DropdownItem(
                        text = label,
                        selected = viewIndex == idx,
                        onClick = { viewIndex = idx },
                    )
                },
            ),
        ),
    ),
)

Scaffold {
    Box {
        TextButton(
            text = "Click to show menu",
            onClick = { showPopup = true },
        )
        OverlayCascadingListPopup(
            show = showPopup,
            entries = entries,
            onDismissRequest = { showPopup = false },
        )
    }
}

Cascading Depth

Cascading depth is capped at 2. Items at the secondary level cannot have their own children; deeper trees are silently ignored.

Component States

Different Alignments

kotlin
OverlayCascadingListPopup(
    show = showPopup,
    entries = entries,
    onDismissRequest = { showPopup = false },
    alignment = PopupPositionProvider.Align.Start,
)

Disable Window Dimming

kotlin
OverlayCascadingListPopup(
    show = showPopup,
    entries = entries,
    onDismissRequest = { showPopup = false },
    enableWindowDim = false,
)

Keep Popup Open After Selection

By default the popup closes when the user picks any leaf item. Set collapseOnSelection = false to keep it open (e.g., for multi-select within a submenu).

kotlin
OverlayCascadingListPopup(
    show = showPopup,
    entries = entries,
    onDismissRequest = { showPopup = false },
    collapseOnSelection = false,
)

Properties

OverlayCascadingListPopup

Property NameTypeDescriptionDefault Value
showBooleanWhether to show the popup.-
entriesList<DropdownEntry>Grouped dropdown entries; top-level items with non-empty children become submenu triggers.-
onDismissRequest() -> UnitCalled when the user requests dismissal (e.g., clicking outside, tapping the back button).-
popupModifierModifierModifier applied to the popup body.Modifier
onDismissFinished(() -> Unit)?Called after the exit animation finishes.null
popupPositionProviderPopupPositionProviderPosition strategy for the primary popup relative to its anchor.ListPopupDefaults.DropdownPositionProvider
alignmentPopupPositionProvider.AlignAlignment of the primary popup.PopupPositionProvider.Align.End
enableWindowDimBooleanWhether to dim the rest of the window while the popup is shown.true
maxHeightDp?Maximum height of either side. Null bounds it by the safe area.null
minWidthDpMinimum width of the popup.200.dp
renderInRootScaffoldBooleanWhether to render the popup in the root (outermost) Scaffold. When true, the popup covers the full screen. When false, it renders within the current Scaffold's bounds with position compensation.true
dropdownColorsDropdownColorsColors used by every row.DropdownDefaults.dropdownColors()
collapseOnSelectionBooleanWhen true, selecting any leaf dismisses the popup.true
Property NameTypeDescriptionDefault ValueRequired
itemsList<DropdownItem>Items shown in this dropdown group-Yes
enabledBooleanWhether this group is enabled. False disables all items; true still respects each item's enabled statetrueNo
Property NameTypeDescriptionDefault ValueRequired
textStringText shown for the item-Yes
enabledBooleanWhether the item can be clicked. Disabled items are graytrueNo
selectedBooleanWhether the item is selectedfalseNo
onClick(() -> Unit)?Callback invoked when the item is clicked. Ignored when children is non-empty (the click expands the submenu instead)nullNo
icon@Composable ((Modifier) -> Unit)?Icon shown before the item textnullNo
summaryString?Summary text shown below the item textnullNo
childrenList<DropdownItem>?Optional submenu items; only the cascading variants render these as a submenu (depth limited to 2)nullNo
Property NameTypeDescription
contentColorColorColor of the option title
summaryColorColorColor of the option summary
containerColorColorBackground color of the option
selectedContentColorColorTitle color of the selected option
selectedSummaryColorColorSummary color of the selected option
selectedContainerColorColorBackground color of the selected option
selectedIndicatorColorColorColor of the selected indicator icon

PopupPositionProvider.Align

ValueDescription
StartAligns the popup to the start of the anchor.
EndAligns the popup to the end of the anchor.
TopStartAligns the popup to the top-start of the anchor.
TopEndAligns the popup to the top-end of the anchor.
BottomStartAligns the popup to the bottom-start of the anchor.
BottomEndAligns the popup to the bottom-end of the anchor.

Changelog

Released under the Apache-2.0 License