Skip to content

Snackbar

Snackbar is a lightweight feedback component in COUI used to display brief messages at the bottom of the screen. It can optionally provide actions such as “Undo” and supports different display durations.

Import

kotlin
import io.github.suqi8.coui.kmp.basic.Snackbar
import io.github.suqi8.coui.kmp.basic.SnackbarHost
import io.github.suqi8.coui.kmp.basic.SnackbarHostState
import io.github.suqi8.coui.kmp.basic.SnackbarDuration
import io.github.suqi8.coui.kmp.basic.SnackbarResult

Basic Usage

The Snackbar is usually used together with Scaffold. You create a SnackbarHostState, pass it to SnackbarHost, and then call showSnackbar to display messages:

kotlin
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

Scaffold(
    snackbarHost = {
        SnackbarHost(state = snackbarHostState)
    },
) { paddingValues ->
    Box(
        modifier = Modifier
            .padding(paddingValues),
    ) {
        TextButton(
            text = "Show message",
            onClick = {
                scope.launch {
                    snackbarHostState.showSnackbar("This is a short message")
                }
            },
        )
    }
}

SnackbarHostState and showSnackbar

SnackbarHostState manages a queue of Snackbar messages.

showSnackbar

kotlin
suspend fun SnackbarHostState.showSnackbar(
    message: String,
    actionLabel: String? = null,
    withDismissAction: Boolean = false,
    duration: SnackbarDuration = SnackbarDuration.Short,
): SnackbarResult
Parameter NameTypeDescriptionDefault ValueRequired
messageStringText shown in the Snackbar-Yes
actionLabelString?Optional label for the action buttonnullNo
withDismissActionBooleanWhether to show a dismiss iconfalseNo
durationSnackbarDurationDuration that the Snackbar stays visibleSnackbarDuration.ShortNo

The return value SnackbarResult indicates whether the Snackbar was dismissed or the action was performed.

Getting the oldest or newest Snackbar

kotlin
suspend fun SnackbarHostState.newestSnackbarData(): SnackbarData?
suspend fun SnackbarHostState.oldestSnackbarData(): SnackbarData?

These helpers allow you to manually dismiss the newest or oldest visible Snackbar via dismiss() or performAction().

SnackbarHost

SnackbarHost is responsible for rendering the Snackbars based on the given SnackbarHostState.

kotlin
@Composable
fun SnackbarHost(
    state: SnackbarHostState,
    modifier: Modifier = Modifier,
    canSwipeToDismiss: Boolean = true,
    content: @Composable (SnackbarData) -> Unit = { Snackbar(it) },
)
Parameter NameTypeDescriptionDefault ValueRequired
stateSnackbarHostStateState that holds the Snackbar queue-Yes
modifierModifierModifier applied to the host containerModifierNo
canSwipeToDismissBooleanWhether Snackbars can be dismissed by swipetrueNo
content@Composable (SnackbarData) -> UnitCustom content for each Snackbar item{ Snackbar(it) }No

In most cases you can keep the default content which uses the built‑in Snackbar composable.

Snackbar

Snackbar defines the default visual style for messages.

kotlin
@Composable
fun Snackbar(
    data: SnackbarData,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    cornerRadius: Dp = SnackbarDefaults.CornerRadius,
    singleLineCornerRadius: Dp = SnackbarDefaults.SingleLineCornerRadius,
    colors: SnackbarColors = SnackbarDefaults.snackbarColors(),
    insideMargin: PaddingValues = SnackbarDefaults.InsideMargin,
)
Parameter NameTypeDescriptionDefault ValueRequired
dataSnackbarDataData describing message and actions-Yes
modifierModifierModifier applied to the Snackbar containerModifierNo
icon(@Composable () -> Unit)?Optional leading icon shown in a 30.dp box (pass it through the content lambda of SnackbarHost)nullNo
cornerRadiusDpCorner radius when the message spans multiple linesSnackbarDefaults.CornerRadiusNo
singleLineCornerRadiusDpCorner radius when the message fits on a single lineSnackbarDefaults.SingleLineCornerRadiusNo
colorsSnackbarColorsColor configuration for the SnackbarSnackbarDefaults.snackbarColors()No
insideMarginPaddingValuesInner padding of the Snackbar content (the end padding collapses to 4.dp when the action button is the trailing element)SnackbarDefaults.InsideMarginNo

SnackbarColors and SnackbarDefaults

SnackbarColors defines the color set used by the Snackbar:

kotlin
data class SnackbarColors(
    val containerColor: Color,
    val contentColor: Color,
    val actionContentColor: Color,
    val dismissActionContentColor: Color,
)

You can create a color configuration via SnackbarDefaults.snackbarColors:

kotlin
val colors = SnackbarDefaults.snackbarColors(
    containerColor = COUITheme.colorScheme.surfaceContainerHighest,
    contentColor = COUITheme.colorScheme.onSurfaceContainer,
    actionContentColor = COUITheme.colorScheme.primary,
    dismissActionContentColor = COUITheme.colorScheme.onSurfaceVariantActions,
)

Constants

SnackbarDefaults also exposes the default corner radii, text style and inside margin used by Snackbar:

Constant NameTypeDescriptionDefault Value
CornerRadiusDpCorner radius when the message spans multiple lines16.dp
SingleLineCornerRadiusDpCorner radius when the message fits on a single line24.dp
InsideMarginPaddingValuesDefault inner padding of the SnackbarPaddingValues(horizontal = 16.dp, vertical = 10.dp)
IconSizeDpSize of the optional leading icon box30.dp

SnackbarDefaults.textStyle() returns the default text style of the message and action label (14sp, medium weight).

SnackbarDuration and SnackbarResult

SnackbarDuration

SnackbarDuration controls how long the Snackbar stays visible:

kotlin
sealed interface SnackbarDuration {
    data object Short : SnackbarDuration
    data object Long : SnackbarDuration
    data object Indefinite : SnackbarDuration
    data class Custom(val durationMillis: Long) : SnackbarDuration
}
OptionDescriptionDuration
ShortShort messageAbout 4 seconds
LongLonger messageAbout 10 seconds
IndefiniteStays until dismissed or action firedUntil dismissed
CustomCustom duration in millisecondsUser‑specified

SnackbarResult

SnackbarResult describes how the Snackbar was completed:

kotlin
enum class SnackbarResult {
    Dismissed,
    ActionPerformed,
}

Advanced Usage

Snackbar with leading icon

Pass a custom content lambda to SnackbarHost to render the built-in Snackbar with an icon:

kotlin
SnackbarHost(state = snackbarHostState) { data ->
    Snackbar(
        data = data,
        icon = {
            Icon(
                imageVector = COUIIcons.Basic.Check,
                contentDescription = null,
                tint = COUITheme.colorScheme.primary
            )
        }
    )
}

Snackbar with action

kotlin
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

TextButton(
    text = "Show action",
    onClick = {
        scope.launch {
            val result = snackbarHostState.showSnackbar(
                message = "This message has an action",
                actionLabel = "Undo",
                duration = SnackbarDuration.Short,
            )
            when (result) {
                SnackbarResult.ActionPerformed -> { /* handle undo */ }
                SnackbarResult.Dismissed -> { /* handle timeout */ }
            }
        }
    },
)

Dismissible and indefinite Snackbar

kotlin
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

TextButton(
    text = "Show indefinite",
    onClick = {
        scope.launch {
            snackbarHostState.showSnackbar(
                message = "Indefinite message, dismiss manually",
                withDismissAction = true,
                duration = SnackbarDuration.Indefinite,
            )
        }
    },
)

TextButton(
    text = "Dismiss oldest",
    onClick = {
        scope.launch {
            snackbarHostState.oldestSnackbarData()?.dismiss()
        }
    },
)

Changelog

Released under the Apache-2.0 License