How to make Material3 ModalBottomSheet non-draggable while keeping internal content scrollable in Jetpack Compose?


Description

I am using Material3 ModalBottomSheet in Jetpack Compose and I want to place a scrollable list inside it.

The problem is that there seems to be a gesture conflict between the scrollable content inside the bottom sheet and the swipe/drag gesture of the ModalBottomSheet itself. When the user scrolls or drags down inside the sheet, the bottom sheet starts moving as well.

I was able to solve this by creating a custom bottom sheet component, but I would prefer to avoid that if possible.

Is there any way to make Material3 ModalBottomSheet non-draggable, while still allowing the content inside it to be scrollable?

Attempts to solve

I tried using confirmValueChange:

val sheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true, confirmValueChange = { newValue -> newValue != SheetValue.Hidden } ) ModalBottomSheet( sheetState = sheetState, onDismissRequest = {}, dragHandle = null ) { Content() }

This prevents the sheet from being hidden, but it does't disable the drag animation itself. The sheet can still be dragged/swiped down slightly and then snaps back.

What I want is to completely disable the swipe/drag behavior of ModalBottomSheet, so that only the internal scrollable list handles vertical gestures.

1
May 21 at 9:50 AM
User AvatarStanisław Olszak
#android#kotlin#android-jetpack-compose

Accepted Answer

To make the Material 3 ModalBottomSheet non-draggable while preserving the independent scrolling of its internal content, you should use the sheetGesturesEnabled parameter.
Passing sheetGesturesEnabled = false disables the top-level swipe-to-dismiss behavior on the bottom sheet itself, resolving the gesture conflict and allowing internal containers (like a LazyColumn or a verticalScroll) to fully handle vertical gestures.

Note: sheetGesturesEnabled was added in Material 3 v1.4.0-alpha02 so you should ensure you're using the latest version in the Compose BOM

@Composable
fun NonDraggableBottomSheet(
    onDismissRequest: () -> Unit
) {
    val sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = true
    )

    ModalBottomSheet(
        onDismissRequest = onDismissRequest,
        sheetState = sheetState,
        // This disables the outer swipe-to-dismiss drag behavior
        sheetGesturesEnabled = false, 
        dragHandle = null
    ) {
        // Your scrollable internal content
        Content()
    }
}
User AvatarMofe Ejegi
May 21 at 10:52 AM
2