New Compose Multiplatform components arrived on Composables UICheck it out →

SnackbarHost

Host for [Snackbar]s to be used in [Scaffold] to properly show, hide and dismiss items based on Material specification and the [hostState].

This component with default parameters comes build-in with [Scaffold], if you need to show a default [Snackbar], use [SnackbarHostState.showSnackbar].

Last updated:

Installation

dependencies {
   implementation("androidx.compose.material3:material3:1.3.0-beta03")
}

Overloads

@Composable
fun SnackbarHost(
    hostState: SnackbarHostState,
    modifier: Modifier = Modifier,
    snackbar: @Composable (SnackbarData) -> Unit = { Snackbar(it) }
)

Parameters

namedescription
hostStatestate of this component to read and show [Snackbar]s accordingly
modifierthe [Modifier] to be applied to this component
snackbarthe instance of the [Snackbar] to be shown at the appropriate time with appearance based on the [SnackbarData] provided as a param

Code Examples

ScaffoldWithSimpleSnackbar

@Composable
@Sampled
@Preview
fun ScaffoldWithSimpleSnackbar() {
    val snackbarHostState = remember { SnackbarHostState() }
    val scope = rememberCoroutineScope()
    Scaffold(
        snackbarHost = { SnackbarHost(snackbarHostState) },
        floatingActionButton = {
            var clickCount by remember { mutableStateOf(0) }
            ExtendedFloatingActionButton(
                onClick = {
                    // show snackbar as a suspend function
                    scope.launch { snackbarHostState.showSnackbar("Snackbar # ${++clickCount}") }
                }
            ) {
                Text("Show snackbar")
            }
        },
        content = { innerPadding ->
            Text(
                text = "Body content",
                modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize()
            )
        }
    )
}

ScaffoldWithCustomSnackbar

@Composable
@Sampled
@Preview
fun ScaffoldWithCustomSnackbar() {
    class SnackbarVisualsWithError(override val message: String, val isError: Boolean) :
        SnackbarVisuals {
        override val actionLabel: String
            get() = if (isError) "Error" else "OK"

        override val withDismissAction: Boolean
            get() = false

        override val duration: SnackbarDuration
            get() = SnackbarDuration.Indefinite
    }

    val snackbarHostState = remember { SnackbarHostState() }
    val scope = rememberCoroutineScope()
    Scaffold(
        snackbarHost = {
            // reuse default SnackbarHost to have default animation and timing handling
            SnackbarHost(snackbarHostState) { data ->
                // custom snackbar with the custom action button color and border
                val isError = (data.visuals as? SnackbarVisualsWithError)?.isError ?: false
                val buttonColor =
                    if (isError) {
                        ButtonDefaults.textButtonColors(
                            containerColor = MaterialTheme.colorScheme.errorContainer,
                            contentColor = MaterialTheme.colorScheme.error
                        )
                    } else {
                        ButtonDefaults.textButtonColors(
                            contentColor = MaterialTheme.colorScheme.inversePrimary
                        )
                    }

                Snackbar(
                    modifier =
                        Modifier.border(2.dp, MaterialTheme.colorScheme.secondary).padding(12.dp),
                    action = {
                        TextButton(
                            onClick = { if (isError) data.dismiss() else data.performAction() },
                            colors = buttonColor
                        ) {
                            Text(data.visuals.actionLabel ?: "")
                        }
                    }
                ) {
                    Text(data.visuals.message)
                }
            }
        },
        floatingActionButton = {
            var clickCount by remember { mutableStateOf(0) }
            ExtendedFloatingActionButton(
                onClick = {
                    scope.launch {
                        snackbarHostState.showSnackbar(
                            SnackbarVisualsWithError(
                                "Snackbar # ${++clickCount}",
                                isError = clickCount % 2 != 0
                            )
                        )
                    }
                }
            ) {
                Text("Show snackbar")
            }
        },
        content = { innerPadding ->
            Text(
                text = "Custom Snackbar Demo",
                modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize()
            )
        }
    )
}