Material 3 Snackbar in Jetpack Compose (with Examples)

Jetpack Compose Material 3 Snackbar

In this article, we’ll learn how to implement the Material 3 Snackbar in Jetpack Compose.

Prerequisites:

What is a Snackbar?

Snackbars display short information about an operation at the bottom of the screen. They contain optional action and dismiss buttons.

Let’s look at the Snackbar APIs in Android Studio.

First, create an empty Compose project and open the MainActivity.kt. Create a MyUI() composable and call it from the onCreate() method. We’ll write our code in it.

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Snackbar
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize()
                    ) {
                        MyUI()
                    }
                }
            }
        }
    }
}

@Composable
fun MyUI() {

}

Jetpack Compose provides Snackbar() API.

@Composable
fun Snackbar(
    modifier: Modifier = Modifier,
    action: @Composable (() -> Unit)? = null,
    dismissAction: @Composable (() -> Unit)? = null,
    actionOnNewLine: Boolean = false,
    shape: Shape = SnackbarDefaults.shape,
    containerColor: Color = SnackbarDefaults.color,
    contentColor: Color = SnackbarDefaults.contentColor,
    actionContentColor: Color = SnackbarDefaults.actionContentColor,
    dismissActionContentColor: Color = SnackbarDefaults.dismissActionContentColor,
    content: @Composable () -> Unit
)

modifier – The Modifier to be applied to this snackbar.

action – Action button of the snackbar.

dismissAction – Close button of the snackbar.

actionOnNewLine – Whether or not action should be put on a separate line. Recommended for action with a long label.

shape – Shape of the snackbar’s container. We can use any shape API that Jetpack Compose provides.

containerColor – The background color of this snackbar. Use Color.Transparent to have no color.

contentColor – The preferred color for content inside this snackbar.

actionContentColor – The preferred content color for the action.

dismissActionContentColor – The preferred content color for the dismissAction.

content – The content of the snackbar. We add Text() here.

Simple Snackbar Example:

Let’s display the snackbar on a button click.

@Composable
fun MyUI() {
    // to display and hide the snackbar
    var showSnackbar by remember {
        mutableStateOf(false)
    }

    Box(modifier = Modifier.fillMaxSize()) {
        Button(
            modifier = Modifier.align(alignment = Alignment.Center), // keep the button at the center of the screen
            onClick = { showSnackbar = !showSnackbar }
        ) {
            Text(text = "${if (showSnackbar) "Hide" else "Show"} Snackbar")
        }

        if (showSnackbar) {
            Snackbar(
                modifier = Modifier
                    .padding(all = 8.dp)
                    .align(alignment = Alignment.BottomCenter) // show the snackbar at the bottom of the screen
            ) {
                Text(text = "This is a Snackbar!")
            }
        }
    }
}

Output:

Simple Snackbar Example

The code is simple. We created a state variable called showSnackbar. It represents if the snackbar should be rendered on the screen or not. Next, we added a Box layout and put a Button() and Snackbar() in it. In the button’s onClick block, we are changing the snackbar’s state.

Action Button:

We can add an action button using the action parameter. Generally, we use TextButton().

@Composable
fun MyUI() {
    var showSnackbar by remember {
        mutableStateOf(false)
    }

    val contextForToast = LocalContext.current.applicationContext

    Box(modifier = Modifier.fillMaxSize()) {
        Button(
            modifier = Modifier.align(alignment = Alignment.Center), // keep the button at the center of the screen
            onClick = { showSnackbar = !showSnackbar }
        ) {
            Text(text = "${if (showSnackbar) "Hide" else "Show"} Snackbar")
        }

        if (showSnackbar) {
            Snackbar(
                modifier = Modifier
                    .padding(all = 8.dp)
                    .align(alignment = Alignment.BottomCenter), // show the snackbar at the bottom of the screen
                action = {
                    TextButton(
                        onClick = {
                            Toast.makeText(contextForToast, "Action Click", Toast.LENGTH_SHORT)
                                .show()
                        }
                    ) {
                        Text(text = "Action")
                    }
                }
            ) {
                Text(text = "This is a Snackbar!")
            }
        }
    }
}

Output:

Action Button

Related: 5 Simple Text Animations in Jetpack Compose

Snackbar with Scaffold:

In the previous examples, we have used the Box layout to display the snackbar. But, it is recommended to use Scaffold instead. For Scaffold, we should use SnackbarHostState, not Snackbar().

@Composable
fun MyUI() {
    val snackbarHostState = remember { SnackbarHostState() }
    val coroutineScope = rememberCoroutineScope()

    var clickCount by remember {
        mutableIntStateOf(0) // or use mutableStateOf(0)
    }

    Scaffold(
        snackbarHost = { SnackbarHost(snackbarHostState) }
    ) { paddingValues ->
        // rest of the app's UI
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues = paddingValues),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Button(onClick = {
                coroutineScope.launch {
                    snackbarHostState.showSnackbar(
                        message = "Snackbar # ${++clickCount}",
                        duration = SnackbarDuration.Short
                    )
                }
            }) {
                Text(text = "Show Snackbar")
            }
        }
    }
}

Output:

Snackbar with Scaffold

The showSnackbar() method looks like this:

suspend fun showSnackbar(
    message: String,
    actionLabel: String? = null,
    withDismissAction: Boolean = false,
    duration: SnackbarDuration =
        if (actionLabel == null) SnackbarDuration.Short else SnackbarDuration.Indefinite
): SnackbarResult

message – Text to be shown in the snackbar.

actionLabel – Optional label to show as a text button in the snackbar.

withDismissAction – A boolean to show the dismiss icon. This is recommended to be set to true when you set SnackbarDuration.Indefinite as the duration.

duration – It indicates how long the snackbar will be shown. There are three values: SnackbarDuration.Short, SnackbarDuration.Long, or SnackbarDuration.Indefinite. Short and Long values show the snack bar for 4 and 10 seconds, respectively. Indefinite shows the snack bar until the user dismisses it or clicks on the action button.

The method returns SnackbarResult.ActionPerformed if action has been clicked or SnackbarResult.Dismissed if snackbar has been dismissed via timeout or by the user.

The advantage of SnackbarHostState is that it ensures that only one snackbar is visible at a time. If the showSnackbar() is called while another snackbar is already visible, the new snackbar will be added to the queue and shown after the current snackbar is dismissed.

Action and Dismiss Buttons:

To display the action button, pass the button text to the actionLabel parameter, and for the dismiss icon, pass true to the withDismissAction parameter.

In the previous code, change the showSnackbar() method.

snackbarHostState.showSnackbar(
    actionLabel = "Action",
    withDismissAction = true,
    message = "Snackbar # ${++clickCount}",
    duration = SnackbarDuration.Short
)

Output:

Action and Dismiss Buttons in Material 3 Jetpack Compose Snackbar

This is all about Material 3 Snackbar in Jetpack Compose. I hope you have learned something new. If you have any doubts, leave a comment below.

Related Articles:


References:

Leave a Comment