How to Make Custom Snackbars in Android: Jetpack Compose Snackbars— A Simple Guide

Binod Basnet
3 min readJul 22, 2024

--

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

--

--