How to Make Custom Snackbars in Android: Jetpack Compose Snackbars— A Simple Guide
If you want just one line of code to show a snackbar throughout your project, you are in the right place. This is a sample that demonstrates how to display a custom snackbar at a production level, ensuring code reusability and dynamism. See the code below:
scope.showSuccessSnackbar("This is my success snackbar")
scope.showErrorSnackbar("This is my error snackbar")
Step 1: Create an Enum Class
enum class SnackbarType {
SUCCESS,
ERROR
}
Step 2: Create an data class
data class SnackbarMessage(
val title: String,
val description: String,
val type: SnackbarType
)
Step 3: Create an object for Snackbar Management.
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
object SnackbarManager {
val snackbarHostState = SnackbarHostState()
private var isSnackbarVisible = false
fun CoroutineScope.showSuccessSnackbar(description: String) {
val message = SnackbarMessage("Success", description, SnackbarType.SUCCESS)
showSnackbar(message)
}
fun CoroutineScope.showErrorSnackbar(description: String) {
val message = SnackbarMessage("Error", description, SnackbarType.ERROR)
showSnackbar(message)
}
private fun CoroutineScope.showSnackbar(snackbarMessage: SnackbarMessage) {
if (!isSnackbarVisible) {
launch {
isSnackbarVisible = true
snackbarHostState.showSnackbar(
message = with(snackbarMessage) { "$title: $description" },
duration = SnackbarDuration.Short
)
isSnackbarVisible = false
}
}
}
}
Step 4: Create a Composable Function for CustomSnackbar
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
fun CustomSnackbar(title: String, description: String, type: SnackbarType) {
val (backgroundColor, textColor) = when (type) {
SnackbarType.ERROR -> Pair(
MaterialTheme.colorScheme.surface,
MaterialTheme.customColorScheme.error
)
SnackbarType.SUCCESS -> Pair(
MaterialTheme.colorScheme.surface,
MaterialTheme.customColorScheme.error
)
}
Card(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp),
colors = CardDefaults.cardColors(
containerColor = backgroundColor,
),
) {
Row(
modifier = Modifier.height(IntrinsicSize.Min),
horizontalArrangement = Arrangement.Center,
) {
VerticalDivider(
color = MaterialTheme.colorScheme.primary,
thickness = 8.dp,
modifier = Modifier
.padding(all = 0.dp)
.fillMaxHeight()
)
Column(modifier = Modifier.padding(all = 12.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
val (icon, tint) = when (type) {
SnackbarType.ERROR -> Pair(
R.drawable.ic_error,
MaterialTheme.customColorScheme.error
)
SnackbarType.SUCCESS -> Pair(
R.drawable.ic_tick,
MaterialTheme.customColorScheme.success
)
}
Icon(
painter = painterResource(id = icon),
contentDescription = "Status Icon",
tint = tint
)
Spacer(modifier = Modifier.padding(all = 4.dp))
CustomNormalText(inputText = title, textColor = textColor)
}
Spacer(modifier = Modifier.padding(all = 4.dp))
CustomNormalText(
inputText = description,
textColor = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 4
)
}
}
}
}
Step 5: Create a Composable Function to Host CustomSnackbar
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHost
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun CustomSnackbarHost() {
Box(modifier = Modifier
.fillMaxSize()
.padding(start = 16.dp, end = 16.dp, top = 24.dp)
)
{
SnackbarHost(
hostState = SnackbarManager.snackbarHostState,
) { data ->
val parts = data.visuals.message.split(": ")
val title = parts[0]
val description = parts.getOrNull(1) ?: ""
val type = if (title == "Error") SnackbarType.ERROR else SnackbarType.SUCCESS
CustomSnackbar(title, description, type)
}
}
}
Step 6: Call CustomSnackbarHost from a Composable Screen to Show Snackbar
@Composable
fun HomeScreen()
{
val scope = rememberCoroutineScope()
Scaffold(snackbarHost = { CustomSnackbarHost() }) { contentPadding ->
Surface(
modifier = Modifier.padding(contentPadding)
) {
scope.showErrorSnackbar("This is my snackbar")
}
}
}
This is a simple tutorial to show a custom snackbar in your Jetpack Compose project.
#JetpackCompose, #Android, #Kotlin, #CustomSnackbar, #Snackbar