The Jetpack Compose Snackbar is a material design component that displays brief messages at the bottom of the screen. Unlike Toast messages, Jetpack Compose Snackbar offers more functionality and customization options. The Snackbar component in Jetpack Compose is designed to provide temporary, actionable feedback to users without interrupting their workflow.
The Jetpack Compose Snackbar component comes with numerous properties that allow for extensive customization. Understanding these properties is crucial for implementing effective Snackbar notifications in your Android applications.
Implementing Jetpack Compose Snackbar involves understanding the SnackbarHost and SnackbarHostState components. The Snackbar system in Jetpack Compose works through a state-based approach that integrates seamlessly with Compose's reactive architecture.
@Composable
fun SnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) { padding ->
Button(
onClick = {
scope.launch {
snackbarHostState.showSnackbar(
message = "This is a Jetpack Compose Snackbar",
actionLabel = "Undo"
)
}
},
modifier = Modifier.padding(padding)
) {
Text("Show Snackbar")
}
}
}
For more complex scenarios, you can customize the Jetpack Compose Snackbar with additional properties and features:
@Composable
fun CustomSnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = {
SnackbarHost(snackbarHostState) { data ->
Snackbar(
snackbarData = data,
backgroundColor = Color(0xFF323232),
contentColor = Color.White,
actionColor = Color.Yellow,
shape = RoundedCornerShape(8.dp),
elevation = 8.dp,
modifier = Modifier.padding(16.dp)
)
}
}
) { padding ->
// Main content
}
}
The Jetpack Compose Snackbar provides three duration options for controlling how long the message remains visible:
Example implementation:
scope.launch {
snackbarHostState.showSnackbar(
message = "Your message here",
actionLabel = "Dismiss",
duration = SnackbarDuration.Long
)
}
The SnackbarHostState is a crucial component for managing Jetpack Compose Snackbar behavior and lifecycle. This state holder coordinates the display, queue management, and dismissal of Snackbar messages in Jetpack Compose applications. Understanding SnackbarHostState is essential for implementing effective notification systems in your Android applications.
The SnackbarHostState class serves as the central state management system for Jetpack Compose Snackbar functionality. It provides a structured approach to handling asynchronous Snackbar operations while maintaining the reactive nature of Compose.
class SnackbarHostState {
val currentSnackbarData: SnackbarData?
suspend fun showSnackbar(
message: String,
actionLabel: String? = null,
duration: SnackbarDuration = SnackbarDuration.Short
): SnackbarResult
}
The showSnackbar() function is the core method of SnackbarHostState that triggers Snackbar display. It's a suspend function that operates within a coroutine scope:
// Full function signature
suspend fun showSnackbar(
message: String,
actionLabel: String? = null,
withDismissAction: Boolean = false,
duration: SnackbarDuration = SnackbarDuration.Short
): SnackbarResult
The showSnackbar() function returns a SnackbarResult enum that indicates how the user interacted with the Snackbar:
enum class SnackbarResult {
ActionPerformed,
Dismissed
}
This allows you to handle different outcomes:
val result = snackbarHostState.showSnackbar(
message = "File deleted",
actionLabel = "Undo"
)
when (result) {
SnackbarResult.ActionPerformed -> {
// User clicked the action button
undoFileDelete()
}
SnackbarResult.Dismissed -> {
// Snackbar was dismissed (timeout or swipe)
logFileDeleteConfirmed()
}
}
SnackbarHostState must be preserved across recompositions using the remember API:
@Composable
fun SnackbarScreen() {
val snackbarHostState = remember { SnackbarHostState() }
// Use rememberCoroutineScope for launching coroutines
val coroutineScope = rememberCoroutineScope()
}
While SnackbarHostState handles queueing internally, you can create custom queue management for complex scenarios:
class CustomSnackbarQueue {
private val queue = mutableListOf<SnackbarData>()
suspend fun enqueue(
snackbarHostState: SnackbarHostState,
message: String,
actionLabel: String? = null,
priority: Priority = Priority.NORMAL
) {
// Custom queue logic
when (priority) {
Priority.HIGH -> {
// Show immediately or insert at front of queue
snackbarHostState.currentSnackbarData?.dismiss()
showSnackbarNow(snackbarHostState, message, actionLabel)
}
Priority.NORMAL -> {
// Add to regular queue
queue.add(SnackbarData(message, actionLabel))
processQueue(snackbarHostState)
}
}
}
}
You can observe the current Snackbar state using Compose's state management:
@Composable
fun SnackbarObserver(snackbarHostState: SnackbarHostState) {
val currentSnackbar = snackbarHostState.currentSnackbarData
LaunchedEffect(currentSnackbar) {
if (currentSnackbar != null) {
// Log or handle the current Snackbar state
analytics.trackSnackbarShown(currentSnackbar.message)
}
}
}
SnackbarHostState integrates seamlessly with Scaffold's snackbarHost parameter:
@Composable
fun MainScreen() {
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackbarHostState) { data ->
// Custom Snackbar layout
Snackbar(
snackbarData = data,
modifier = Modifier.padding(16.dp)
)
}
}
) { paddingValues ->
// Screen content
}
}
You can create different types of Snackbars by extending SnackbarHostState functionality:
class TypedSnackbarHostState {
enum class SnackbarType { SUCCESS, ERROR, WARNING, INFO }
suspend fun showTypedSnackbar(
hostState: SnackbarHostState,
message: String,
type: SnackbarType,
actionLabel: String? = null
): SnackbarResult {
// Add type information to the message or use custom data
return hostState.showSnackbar(
message = message,
actionLabel = actionLabel,
duration = when (type) {
SnackbarType.ERROR -> SnackbarDuration.Long
SnackbarType.SUCCESS -> SnackbarDuration.Short
else -> SnackbarDuration.Short
}
)
}
}
Jetpack Compose Snackbar offers extensive customization options for creating unique and brand-aligned notification experiences:
Snackbar(
snackbarData = data,
backgroundColor = MaterialTheme.colors.primary,
contentColor = MaterialTheme.colors.onPrimary,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
modifier = Modifier.fillMaxWidth()
)
You can customize the action button in Jetpack Compose Snackbar with different styles and behaviors:
Snackbar(
snackbarData = data,
action = {
TextButton(
onClick = { /* Handle action */ },
colors = ButtonDefaults.textButtonColors(
contentColor = Color.Yellow
)
) {
Text(data.actionLabel ?: "")
}
}
)
fun showSuccessSnackbar(snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
scope.launch {
snackbarHostState.showSnackbar(
message = "Operation successful!",
actionLabel = "View",
duration = SnackbarDuration.Short
)
}
}
fun showErrorSnackbar(snackbarHostState: SnackbarHostState, scope: CoroutineScope, error: String) {
scope.launch {
snackbarHostState.showSnackbar(
message = "Error: $error",
actionLabel = "Retry",
duration = SnackbarDuration.Long
)
}
}
fun showUndoSnackbar(snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "Item deleted",
actionLabel = "Undo",
duration = SnackbarDuration.Long
)
when (result) {
SnackbarResult.ActionPerformed -> {
// Handle undo action
}
SnackbarResult.Dismissed -> {
// Snackbar was dismissed without action
}
}
}
}