Material 3 Bottom Sheets in Android with Developer Documentation

Material 3 Bottom Sheets

Overview

Bottom Sheets are surfaces anchored to the screen bottom, displaying supplementary content.

Material 3 Bottom Sheets support two variants: Standard (persistent, co-exists with main UI) and Modal (blocks main UI, dialog-like). Using BottomSheetBehavior for Standard and BottomSheetDialogFragment for Modal, they offer states like STATE_COLLAPSED, STATE_EXPANDED, and STATE_HIDDEN, with customizable behaviors like peek height and draggability. This guide covers implementation, accessibility, and theming.

Bottom Sheet variants

Getting Started

  • Add Material Components for Android library dependency
  • Use BottomSheetBehavior for Standard or BottomSheetDialogFragment for Modal
  • Apply Theme.Material3.* for styling
  • Include BottomSheetDragHandleView for accessibility

Accessibility

  • Set android:contentDescription on content for TalkBack
  • Use BottomSheetDragHandleView (48dp min size) for drag support
  • Ensure Modal sheets dismiss clearly for screen readers

Behavior and States

  • States: STATE_COLLAPSED, STATE_EXPANDED, STATE_HALF_EXPANDED, STATE_HIDDEN, STATE_DRAGGING, STATE_SETTLING
  • Configure peekHeight, hideable, fitToContents, skipCollapsed, draggable
  • Handle state changes with BottomSheetCallback
      
val bottomSheet = findViewById<FrameLayout>(R.id.standard_bottom_sheet)
val behavior = BottomSheetBehavior.from(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.peekHeight = 100
behavior.isHideable = true
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onStateChanged(bottomSheet: View, newState: Int) {
        // Handle state change
    }
    override fun onSlide(bottomSheet: View, slideOffset: Float) {
        // Handle slide
    }
})
      
    

Bottom Sheet Variants

  • Standard: Persistent, co-exists with main UI
  • Modal: Blocks main UI, dialog-like with scrim

Standard Bottom Sheet

Standard Bottom Sheet
  • Persistent, allows simultaneous UI interaction
  • Ideal for secondary content like maps or controls

Example

      
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- Main content -->
    <FrameLayout
        android:id="@+id/standard_bottom_sheet"
        style="@style/Widget.Material3.BottomSheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
        app:behavior_peekHeight="100dp"
        app:behavior_hideable="false">
        <com.google.android.material.bottomsheet.BottomSheetDragHandleView
            android:id="@+id/drag_handle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:contentDescription="@string/drag_handle_desc"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/title"
                android:textAppearance="?attr/textAppearanceTitleMedium"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@string/supporting_text"
                android:textAppearance="?attr/textAppearanceBodyMedium"/>
        </LinearLayout>
    </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
      
    
      
val standardBottomSheet = findViewById<FrameLayout>(R.id.standard_bottom_sheet)
val behavior = BottomSheetBehavior.from(standardBottomSheet)
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
      
    

Standard Bottom Sheet Anatomy

Standard Bottom Sheet anatomy diagram
Component Description Collapsed State Expanded State Hidden State
Container Content container, 1dp elevation Visible at peekHeight (e.g., 100dp) Visible at max height (640dp) Hidden
Drag Handle Optional, 48dp min size for accessibility Visible if set Visible if set Hidden

Modal Bottom Sheet

Modal Bottom Sheet
  • Blocks main UI with a scrim
  • Ideal for focused choices or dialogs

Example

      
<!-- res/layout/modal_bottom_sheet_content.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">
    <com.google.android.material.bottomsheet.BottomSheetDragHandleView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:contentDescription="@string/drag_handle_desc"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/title"
        android:textAppearance="?attr/textAppearanceTitleMedium"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/supporting_text"
        android:textAppearance="?attr/textAppearanceBodyMedium"/>
    <com.google.android.material.button.MaterialButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="@string/action"
        style="?attr/materialButtonStyle"/>
</LinearLayout>
      
    
      
class ModalBottomSheet : BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.modal_bottom_sheet_content, container, false)
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val behavior = (dialog as BottomSheetDialog).behavior
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
    }
    
    companion object {
        const val TAG = "ModalBottomSheet"
    }
}
// In Activity
val modalBottomSheet = ModalBottomSheet()
modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG)
      
    

Modal Bottom Sheet Anatomy

Modal Bottom Sheet anatomy diagram
Component Description Collapsed State Expanded State Hidden State
Container Modal container, 1dp elevation Visible at peekHeight (e.g., auto) Visible at max height (640dp) Hidden
Drag Handle Optional, 48dp min size for accessibility Visible if set Visible if set Hidden
Scrim Dims main UI Visible, semi-transparent Visible, semi-transparent Hidden

Attributes and Usage

Element Attribute Related Method(s) Default Value Usage Description
Sheet app:backgroundTint N/A ?attr/colorSurfaceContainerLow Sets background color
Sheet app:shapeAppearance N/A ?attr/shapeAppearanceCornerExtraLarge Sets corner shape
Sheet android:elevation N/A 1dp Sets elevation
Sheet android:maxWidth setMaxWidth, getMaxWidth 640dp Sets max width
Behavior app:behavior_peekHeight setPeekHeight, getPeekHeight auto Sets collapsed height
Behavior app:behavior_hideable setHideable, isHideable false (Standard), true (Modal) Allows hiding sheet
Behavior app:behavior_fitToContents setFitToContents, isFitToContents true Fits sheet to content height
Behavior app:behavior_skipCollapsed setSkipCollapsed, getSkipCollapsed false Skips collapsed state
Behavior app:behavior_draggable setDraggable, isDraggable true Enables dragging

Theming Bottom Sheets

Themed Bottom Sheet
  • Customize color and shape
  • Use res/values/styles.xml for theming

Example

      
<style name="Theme.App" parent="Theme.Material3.*">
    <item name="bottomSheetDialogTheme">@style/ThemeOverlay.App.BottomSheetDialog</item>
</style>
<style name="ThemeOverlay.App.BottomSheetDialog" parent="ThemeOverlay.Material3.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/Widget.App.BottomSheet</item>
</style>
<style name="Widget.App.BottomSheet" parent="Widget.Material3.BottomSheet.Modal">
    <item name="backgroundTint">@color/shrine_pink_light</item>
    <item name="shapeAppearance">@style/ShapeAppearance.App.LargeComponent</item>
</style>
<style name="ShapeAppearance.App.LargeComponent" parent="ShapeAppearance.Material3.LargeComponent">
    <item name="cornerFamily">cut</item>
    <item name="cornerSize">24dp</item>
</style>
      
    

Material Design Documentation

  • Adheres to Material Design guidelines for Bottom Sheets
  • Covers design, behavior, theming specifications
  • Includes accessibility and state management
  • Refer to Material Design documentation for full details

FAQ

What are Material 3 Bottom Sheets?

  • Surfaces anchored to the screen bottom for supplementary content

How many variants are there?

  • Two variants: Standard and Modal

When to use a Modal Bottom Sheet?

  • Use for focused choices that block main UI interaction

How to make them accessible?

  • Set content descriptions; use BottomSheetDragHandleView

Can I customize appearance?

  • Yes, theme via res/values/styles.xml

How to add the Material 3 library?

  • Include Material Components for Android library

Are there updates for the latest standards?

  • Reflects latest Material 3 standards for Bottom Sheets

Post a Comment

Previous Post Next Post