How to create Bottom Sheet in Jetpack Compose

How to create Bottom Sheet in Jetpack Compose

What is Bottom sheet?

Bottom Sheet a useful component in Material Design is just like a dialog that slides up from the bottom of the screen contain. The bottom sheet provides an easy and flexible way for displaying the components and menus in an easy way to the user with the best user experiences. It looks more attractive than Dialog. 

There are two types of bottom sheets:
1. Standard and 
2. Modal 

In this tutorial we will learn to create both type of bottom sheet one by one 

Create a New Project and select Empty Activity In my case, application name is Coding Bihar you can use any other name.

drawing of a cat


Create a separate file for Bottom Sheet and named it as BottomSample.

MainActivity

Copy this code →
package com.example.codingbihar

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.example.codingbihar.ui.theme.CodingBiharTheme

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CodingBiharTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    BottomSample()
                    }
            }
        }
    }
}

Bottom Sheet

Copy this code →

package com.example.codingbihar

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSample() {
    val sheet = rememberBottomSheetScaffoldState()
    rememberCoroutineScope()
    BottomSheetScaffold(
        scaffoldState = sheet,
        containerColor = Color.Green,
        sheetContainerColor = Color.Red,
        sheetContent = {
            Column(
                Modifier
                    .padding(12.dp)
                    .fillMaxWidth()
                    .height(300.dp)
            ) {
                Text(text = "  Action Button",
               fontStyle = FontStyle.Italic,
                fontWeight = FontWeight.ExtraBold,
                fontFamily = FontFamily.Cursive,
                fontSize = 30.sp)
                Divider(modifier = Modifier
                    .padding(6.dp)
                    .fillMaxWidth()
                    .height(3.dp),
                    color = Color.Green)
                Icon(imageVector = Icons.Default.Share,
                    modifier = Modifier
                        .padding(6.dp)
                        .size(36.dp),
                    contentDescription = "")
                Divider(modifier = Modifier
                    .fillMaxWidth()
                    .height(3.dp),
                color = Color.Green)
                Icon(imageVector = Icons.Default.Add,
                    modifier = Modifier
                        .padding(6.dp)
                        .size(36.dp),
                    contentDescription = "")
                Divider(modifier = Modifier
                    .fillMaxWidth()
                    .height(3.dp),
                    color = Color.Green)
                Icon(imageVector = Icons.Default.Share,
                    modifier = Modifier
                        .padding(6.dp)
                        .size(36.dp),
                    contentDescription = "")
                Divider(modifier = Modifier
                    .fillMaxWidth()
                    .height(3.dp),
                    color = Color.Green)
                Icon(imageVector = Icons.Outlined.Delete,
                    modifier = Modifier
                        .padding(6.dp)
                        .size(36.dp),
                    contentDescription = "")
                Divider(modifier = Modifier
                    .fillMaxWidth()
                    .height(3.dp),
                    color = Color.Green)
            }

    },
        sheetPeekHeight = 28.dp

    ) {
        Box(modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center){
            Text(text = "Bottom Sheet", fontSize = 24.sp)
        }
    }
    }

OUTPUT


drawing of a catdrawing of a cat


Modal Sheet


Copy this code →
package com.example.codingbihar

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ModalSheets() {
    var openBottomSheet by rememberSaveable { mutableStateOf(false) }
    var skipPartiallyExpanded by remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope()
    val bottomSheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = skipPartiallyExpanded
    )

// App content
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Row(
            Modifier.toggleable(
                value = skipPartiallyExpanded,
                role = Role.Checkbox,
                onValueChange = { checked -> skipPartiallyExpanded = checked }
            )
        ) {
            Checkbox(checked = skipPartiallyExpanded, onCheckedChange = null)
            Spacer(Modifier.width(16.dp))
            Text("Skip partially expanded State")
        }
        Button(onClick = { openBottomSheet = !openBottomSheet }) {
            Text(text = "Show Bottom Sheet")
        }
    }
// Sheet content
    if (openBottomSheet) {
        androidx.compose.material3.ModalBottomSheet(
            onDismissRequest = { openBottomSheet = false },
            sheetState = bottomSheetState
        ) {
            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.Center
            ) {
                Button(
                    // Note: If you provide logic outside of onDismissRequest to remove the sheet,
                    // you must additionally handle intended state cleanup, if any.
                    onClick = {
                        scope.launch { bottomSheetState.hide() }.invokeOnCompletion {
                            if (!bottomSheetState.isVisible) {
                                openBottomSheet = false
                            }
                        }
                    }
                ) {
                    Text("Hide Bottom Sheet")
                }
            }
            var text by remember { mutableStateOf("Bottom") }
            OutlinedTextField(value = text, onValueChange = { text = it })
            LazyColumn {
                items(50) {
                    ListItem(
                        headlineContent = { Text("Item $it") },
                        leadingContent = {
                            Icon(
                                Icons.Default.Favorite,
                                contentDescription = "Localized description"
                            )
                        }
                    )
                }
            }
        }
    }
}

OUTPUT


drawing of a catdrawing of a cat

drawing of a cat

**********************End***********************