DEV Community

myougaTheAxo
myougaTheAxo

Posted on

BottomSheet in Jetpack Compose: Modal & Standard Sheet Guide

BottomSheet in Jetpack Compose: Modal & Standard Sheet Guide

Jetpack Compose provides powerful APIs for creating bottom sheets that appear from the bottom of the screen. Whether you need a simple modal overlay or a resizable sheet with special behavior, Compose has you covered.

ModalBottomSheet: Simple Overlay

ModalBottomSheet is the simplest approach for displaying temporary content:

var showBottomSheet by remember { mutableStateOf(false) }

if (showBottomSheet) {
    ModalBottomSheet(
        onDismissRequest = { showBottomSheet = false },
        modifier = Modifier.fillMaxWidth()
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text("Choose an option", style = MaterialTheme.typography.headlineSmall)
            Button(onClick = { showBottomSheet = false }) {
                Text("Option 1")
            }
        }
    }
}

Button(onClick = { showBottomSheet = true }) {
    Text("Show Bottom Sheet")
}
Enter fullscreen mode Exit fullscreen mode

BottomSheetScaffold: Resizable Sheet

For sheets that can be expanded and collapsed, use BottomSheetScaffold:

val sheetState = rememberBottomSheetScaffoldState()
val scope = rememberCoroutineScope()

BottomSheetScaffold(
    scaffoldState = sheetState,
    sheetContent = {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp)
                .imePadding()
        ) {
            Text("Expandable Content")
            TextField(
                value = "",
                onValueChange = {},
                label = { Text("Enter text") },
                modifier = Modifier.fillMaxWidth()
            )
        }
    },
    sheetPeekHeight = 56.dp
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Button(onClick = {
            scope.launch {
                sheetState.bottomSheetState.expand()
            }
        }) {
            Text("Expand Sheet")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

skipPartiallyExpanded: Control Snap Behavior

Control whether the sheet snaps to partial height or expands fully:

SheetState(
    skipPartiallyExpanded = true,
    density = LocalDensity.current
)
Enter fullscreen mode Exit fullscreen mode

Programmatic Control: Hide & Expand

Use coroutines to control sheet state programmatically:

val scope = rememberCoroutineScope()
val sheetState = rememberBottomSheetScaffoldState()

Button(onClick = {
    scope.launch {
        if (sheetState.bottomSheetState.isVisible) {
            sheetState.bottomSheetState.hide()
        } else {
            sheetState.bottomSheetState.expand()
        }
    }
}) {
    Text("Toggle Sheet")
}
Enter fullscreen mode Exit fullscreen mode

Forms Inside BottomSheet with imePadding

When using text inputs, add imePadding() to prevent keyboard overlap:

BottomSheetScaffold(
    sheetContent = {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp)
                .imePadding()
        ) {
            var name by remember { mutableStateOf("") }

            TextField(
                value = name,
                onValueChange = { name = it },
                label = { Text("Name") },
                modifier = Modifier.fillMaxWidth()
            )

            Button(
                onClick = { /* Handle submission */ },
                modifier = Modifier.align(Alignment.End)
            ) {
                Text("Submit")
            }
        }
    }
)
Enter fullscreen mode Exit fullscreen mode

Custom Snackbar Integration

Combine bottom sheets with Snackbars for feedback:

val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

Scaffold(
    snackbarHost = { SnackbarHost(snackbarHostState) }
) {
    var showSheet by remember { mutableStateOf(false) }

    if (showSheet) {
        ModalBottomSheet(
            onDismissRequest = { showSheet = false }
        ) {
            Button(onClick = {
                scope.launch {
                    snackbarHostState.showSnackbar("Action completed!")
                    showSheet = false
                }
            }) {
                Text("Complete Action")
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  • Use ModalBottomSheet for simple dialogs and menus
  • Use BottomSheetScaffold when the sheet is part of the main layout
  • Always add imePadding() when bottom sheets contain text inputs
  • Control sheet state with rememberCoroutineScope() for smooth animations
  • Combine with SnackbarHost for user feedback

Bottom sheets are a versatile UI pattern that enhance user experience by keeping important actions accessible without full navigation.


8 Android App Templates → https://myougatheax.gumroad.com

Top comments (0)