Jetpack Compose Toast

Toasts are brief notifications that provide simple feedback about an operation. They appear at the bottom of the screen, contain only text messages, and automatically disappear after a timeout.

Implementing Toast in Jetpack Compose

Since Toast is part of the Android framework and not specific to Compose, we need to access the context to display it in our Compose UI.

import android.widget.Toast  
import androidx.compose.foundation.layout.Column  
import androidx.compose.foundation.layout.Spacer  
import androidx.compose.foundation.layout.height  
import androidx.compose.foundation.layout.padding  
import androidx.compose.material.Button  
import androidx.compose.material.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.platform.LocalContext  
import androidx.compose.ui.unit.dp  
  
@Composable  
fun ToastExample() {  
    // Get the current context  
    val context = LocalContext.current  
      
    Column(modifier = Modifier.padding(16.dp)) {  
        Button(  
            onClick = {  
                // Show a short toast message  
                Toast.makeText(  
                    context,  
                    "This is a short Toast message",  
                    Toast.LENGTH_SHORT  
                ).show()  
            }  
        ) {  
            Text("Show Short Toast")  
        }  
          
        Spacer(modifier = Modifier.height(8.dp))  
          
        Button(  
            onClick = {  
                // Show a long toast message  
                Toast.makeText(  
                    context,  
                    "This is a longer Toast message that stays visible for more time",  
                    Toast.LENGTH_LONG  
                ).show()  
            }  
        ) {  
            Text("Show Long Toast")  
        }  
    }  
}  

Key Properties of Toast in Compose Applications

1. Duration

Toasts have two standard durations:

  • Toast.LENGTH_SHORT: Displays for approximately 2 seconds
  • Toast.LENGTH_LONG: Displays for approximately 3.5 seconds

2. Position

By default, toasts appear at the bottom of the screen, but you can customize their position:

import android.view.Gravity  
import android.widget.Toast  
import androidx.compose.foundation.layout.Column  
import androidx.compose.foundation.layout.padding  
import androidx.compose.material.Button  
import androidx.compose.material.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.platform.LocalContext  
import androidx.compose.ui.unit.dp  
  
@Composable  
fun CustomPositionToastExample() {  
    val context = LocalContext.current  
      
    Column(modifier = Modifier.padding(16.dp)) {  
        Button(  
            onClick = {  
                val toast = Toast.makeText(  
                    context,  
                    "Toast at the top of screen",  
                    Toast.LENGTH_SHORT  
                )  
                // Set the gravity to top  
                toast.setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 50)  
                toast.show()  
            }  
        ) {  
            Text("Top Toast")  
        }  
          
        Button(  
            onClick = {  
                val toast = Toast.makeText(  
                    context,  
                    "Toast at the center of screen",  
                    Toast.LENGTH_SHORT  
                )  
                // Set the gravity to center  
                toast.setGravity(Gravity.CENTER, 0, 0)  
                toast.show()  
            }  
        ) {  
            Text("Center Toast")  
        }  
          
        Button(  
            onClick = {  
                val toast = Toast.makeText(  
                    context,  
                    "Toast at the bottom-right of screen",  
                    Toast.LENGTH_SHORT  
                )  
                // Set the gravity to bottom-right  
                toast.setGravity(Gravity.BOTTOM or Gravity.END, 20, 20)  
                toast.show()  
            }  
        ) {  
            Text("Bottom-Right Toast")  
        }  
    }  
}  

3. Custom Toast Layout

For more complex needs, you can create custom toast layouts:

import android.view.Gravity  
import android.view.LayoutInflater  
import android.widget.ImageView  
import android.widget.TextView  
import android.widget.Toast  
import androidx.compose.foundation.layout.padding  
import androidx.compose.material.Button  
import androidx.compose.material.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.platform.LocalContext  
import androidx.compose.ui.unit.dp  
  
@Composable  
fun CustomLayoutToastExample() {  
    val context = LocalContext.current  
      
    Button(  
        onClick = {  
            // Inflate the custom layout  
            val inflater = LayoutInflater.from(context)  
            val layout = inflater.inflate(R.layout.custom_toast_layout, null)  
              
            // Set the text and image  
            val text = layout.findViewById<TextView>(R.id.toast_text)  
            text.text = "Custom Toast with Image"  
              
            val image = layout.findViewById<ImageView>(R.id.toast_image)  
            image.setImageResource(R.drawable.ic_notification)  
              
            // Create and show the Toast  
            val toast = Toast(context)  
            toast.setGravity(Gravity.CENTER, 0, 0)  
            toast.duration = Toast.LENGTH_LONG  
            toast.view = layout  
            toast.show()  
        },  
        modifier = Modifier.padding(16.dp)  
    ) {  
        Text("Show Custom Toast")  
    }  
}  
  
// Note: You'll need to create a layout file named custom_toast_layout.xml  
// Example layout:  
/*  
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/custom_toast_layout"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:background="@drawable oast_background"  
    android:orientation="horizontal"  
    android:padding="16dp">  
  
    <ImageView  
        android:id="@+id oast_image"  
        android:layout_width="24dp"  
        android:layout_height="24dp"  
        android:layout_marginEnd="8dp"  
        android:contentDescription="Toast Icon" />  
  
    <TextView  
        android:id="@+id oast_text"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:textColor="#FFFFFF" />  
</LinearLayout>  
*/  

Creating a Reusable Toast Function for Compose

For better code organization and reusability, let's create a helper function for showing toasts:

import android.content.Context  
import android.view.Gravity  
import android.widget.Toast  
import androidx.compose.runtime.Composable  
import androidx.compose.runtime.rememberCoroutineScope  
import androidx.compose.ui.platform.LocalContext  
import kotlinx.coroutines.launch  
  
/**  
 * Shows a toast message with the specified parameters.  
 *   
 * @param message The message to display.  
 * @param duration The duration for which the toast should be visible.  
 * @param gravity The position of the toast on the screen.  
 * @param xOffset The x-offset from the specified gravity.  
 * @param yOffset The y-offset from the specified gravity.  
 */  
fun Context.showToast(  
    message: String,  
    duration: Int = Toast.LENGTH_SHORT,  
    gravity: Int = Gravity.BOTTOM,  
    xOffset: Int = 0,  
    yOffset: Int = 0  
) {  
    val toast = Toast.makeText(this, message, duration)  
    toast.setGravity(gravity, xOffset, yOffset)  
    toast.show()  
}  
  
/**  
 * A composable function that provides an easy way to show toasts from within composable functions.  
 */  
@Composable  
fun rememberToastHelper(): ToastHelper {  
    val context = LocalContext.current  
    val scope = rememberCoroutineScope()  
    return remember { ToastHelper(context, scope) }  
}  
  
/**  
 * Helper class for showing toasts from composable functions.  
 */  
class ToastHelper(  
    private val context: Context,  
    private val scope: CoroutineScope  
) {  
    /**  
     * Shows a toast message.  
     *   
     * @param message The message to display.  
     * @param duration The duration for which the toast should be visible.  
     */  
    fun showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {  
        scope.launch {  
            Toast.makeText(context, message, duration).show()  
        }  
    }  
      
    /**  
     * Shows a positioned toast message.  
     *   
     * @param message The message to display.  
     * @param duration The duration for which the toast should be visible.  
     * @param gravity The position of the toast on the screen.  
     * @param xOffset The x-offset from the specified gravity.  
     * @param yOffset The y-offset from the specified gravity.  
     */  
    fun showPositionedToast(  
        message: String,   
        duration: Int = Toast.LENGTH_SHORT,  
        gravity: Int = Gravity.CENTER,  
        xOffset: Int = 0,  
        yOffset: Int = 0  
    ) {  
        scope.launch {  
            val toast = Toast.makeText(context, message, duration)  
            toast.setGravity(gravity, xOffset, yOffset)  
            toast.show()  
        }  
    }  
}  

Using the Toast Helper in Compose UI

Now let's see how to use our reusable toast helper in a practical example:

import android.view.Gravity  
import android.widget.Toast  
import androidx.compose.foundation.layout.Column  
import androidx.compose.foundation.layout.Spacer  
import androidx.compose.foundation.layout.fillMaxSize  
import androidx.compose.foundation.layout.height  
import androidx.compose.foundation.layout.padding  
import androidx.compose.material.Button  
import androidx.compose.material.OutlinedTextField  
import androidx.compose.material.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.runtime.getValue  
import androidx.compose.runtime.mutableStateOf  
import androidx.compose.runtime.remember  
import androidx.compose.runtime.setValue  
import androidx.compose.ui.Alignment  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.platform.LocalContext  
import androidx.compose.ui.unit.dp  
  
@Composable  
fun ToastDemoScreen() {  
    val context = LocalContext.current  
    // Using our custom toast helper  
    val toastHelper = rememberToastHelper()  
      
    var messageText by remember { mutableStateOf("Hello, Toast!") }  
      
    Column(  
        modifier = Modifier  
            .fillMaxSize()  
            .padding(16.dp),  
        horizontalAlignment = Alignment.CenterHorizontally  
    ) {  
        OutlinedTextField(  
            value = messageText,  
            onValueChange = { messageText = it },  
            label = { Text("Toast Message") }  
        )  
          
        Spacer(modifier = Modifier.height(16.dp))  
          
        Button(onClick = {  
            // Using extension function directly  
            context.showToast(messageText)  
        }) {  
            Text("Show Simple Toast")  
        }  
          
        Spacer(modifier = Modifier.height(8.dp))  
          
        Button(onClick = {  
            // Using toast helper  
            toastHelper.showToast(messageText, Toast.LENGTH_LONG)  
        }) {  
            Text("Show Long Toast")  
        }  
          
        Spacer(modifier = Modifier.height(8.dp))  
          
        Button(onClick = {  
            // Using positioned toast  
            toastHelper.showPositionedToast(  
                message = messageText,  
                duration = Toast.LENGTH_SHORT,  
                gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL,  
                yOffset = 50  
            )  
        }) {  
            Text("Show Top Toast")  
        }  
          
        Spacer(modifier = Modifier.height(8.dp))  
          
        Button(onClick = {  
            // Using extension function with custom position  
            context.showToast(  
                message = messageText,  
                duration = Toast.LENGTH_SHORT,  
                gravity = Gravity.CENTER,  
                xOffset = 0,  
                yOffset = 0  
            )  
        }) {  
            Text("Show Center Toast")  
        }  
    }  
}  

Best Practices for Using Toast in Jetpack Compose

1. Keep Messages Short and Concise

Toasts are designed for brief messages. If your message is longer than a few words, consider using a Snackbar instead.

// Good  
"Item saved"  
  
// Bad  
"Your item has been successfully saved to the database and will be available for future use"  

2. Use Toast for Non-Critical Information

Toasts automatically disappear and don't require user interaction. Use them for informational messages that don't require user action.

// Good usage of Toast  
Toast.makeText(context, "Settings updated", Toast.LENGTH_SHORT).show()  
  
// Better with Snackbar (when action is needed)  
Snackbar.make(view, "No internet connection", Snackbar.LENGTH_LONG)  
    .setAction("Retry") { /* retry logic */ }  
    .show()  

3. Don't Overuse Toasts

Too many toast messages can annoy users. Use them sparingly for important but non-critical information.

4. Consider Accessibility

Toast messages disappear automatically, which can cause issues for users with accessibility needs. Consider providing alternative feedback methods for critical information.

Common Toast Implementation Patterns in Compose

1. Toast with ViewModel

import android.app.Application  
import android.widget.Toast  
import androidx.compose.runtime.Composable  
import androidx.compose.runtime.LaunchedEffect  
import androidx.compose.ui.platform.LocalContext  
import androidx.lifecycle.AndroidViewModel  
import androidx.lifecycle.viewmodel.compose.viewModel  
import kotlinx.coroutines.flow.MutableSharedFlow  
import kotlinx.coroutines.flow.asSharedFlow  
  
// Event class for showing toast  
sealed class UiEvent {  
    data class ShowToast(val message: String, val duration: Int = Toast.LENGTH_SHORT) : UiEvent()  
}  
  
// ViewModel with toast event  
class ToastViewModel(application: Application) : AndroidViewModel(application) {  
      
    private val _uiEvent = MutableSharedFlow<UiEvent>()  
    val uiEvent = _uiEvent.asSharedFlow()  
      
    // Function to show toast  
    suspend fun showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {  
        _uiEvent.emit(UiEvent.ShowToast(message, duration))  
    }  
      
    // Example function that might trigger a toast  
    fun saveData(data: String) {  
        // Save logic...  
        // After saving  
        viewModelScope.launch {  
            showToast("Data saved successfully")  
        }  
    }  
}  
  
// Composable to collect toast events  
@Composable  
fun ToastEventCollector(viewModel: ToastViewModel = viewModel()) {  
    val context = LocalContext.current  
      
    LaunchedEffect(key1 = true) {  
        viewModel.uiEvent.collect { event ->  
            when (event) {  
                is UiEvent.ShowToast -> {  
                    Toast.makeText(context, event.message, event.duration).show()  
                }  
            }  
        }  
    }  
}  
  
// Usage in your UI  
@Composable  
fun ToastWithViewModelScreen(viewModel: ToastViewModel = viewModel()) {  
    // Collect toast events  
    ToastEventCollector(viewModel)  
      
    // Your UI content  
    Column {  
        Button(onClick = {  
            viewModel.viewModelScope.launch {  
                viewModel.showToast("Button clicked!")  
            }  
        }) {  
            Text("Show Toast from ViewModel")  
        }  
    }  
}  

2. Creating a Custom Toast-Like Composable

For full control over appearance and behavior, you can create a toast-like composable:

import androidx.compose.animation.AnimatedVisibility  
import androidx.compose.animation.core.MutableTransitionState  
import androidx.compose.animation.core.tween  
import androidx.compose.animation.fadeIn  
import androidx.compose.animation.fadeOut  
import androidx.compose.animation.slideInVertically  
import androidx.compose.animation.slideOutVertically  
import androidx.compose.foundation.background  
import androidx.compose.foundation.layout.Box  
import androidx.compose.foundation.layout.fillMaxSize  
import androidx.compose.foundation.layout.padding  
import androidx.compose.foundation.shape.RoundedCornerShape  
import androidx.compose.material.Card  
import androidx.compose.material.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.runtime.LaunchedEffect  
import androidx.compose.runtime.mutableStateOf  
import androidx.compose.runtime.remember  
import androidx.compose.ui.Alignment  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.graphics.Color  
import androidx.compose.ui.text.style.TextAlign  
import androidx.compose.ui.unit.dp  
import androidx.compose.ui.unit.sp  
import kotlinx.coroutines.delay  
  
/**  
 * A custom composable that mimics the behavior of a Toast but with full control  
 * over appearance and animation.  
 *   
 * @param message The message to display.  
 * @param duration How long the toast should be visible in milliseconds.  
 * @param modifier Modifier for the toast container.  
 */  
@Composable  
fun ComposeToast(  
    message: String,  
    duration: Long = 2000L,  
    modifier: Modifier = Modifier  
) {  
    Box(  
        modifier = Modifier.fillMaxSize(),  
        contentAlignment = Alignment.BottomCenter  
    ) {  
        val visible = remember { MutableTransitionState(false).apply { targetState = true } }  
          
        LaunchedEffect(key1 = message) {  
            delay(duration)  
            visible.targetState = false  
        }  
          
        AnimatedVisibility(  
            visibleState = visible,  
            enter = fadeIn(animationSpec = tween(300)) +   
                   slideInVertically(animationSpec = tween(300)) { fullHeight -> fullHeight },  
            exit = fadeOut(animationSpec = tween(300)) +   
                   slideOutVertically(animationSpec = tween(300)) { fullHeight -> fullHeight }  
        ) {  
            Card(  
                modifier = modifier  
                    .padding(16.dp),  
                shape = RoundedCornerShape(8.dp),  
                backgroundColor = Color(0xFF323232)  
            ) {  
                Text(  
                    text = message,  
                    modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),  
                    color = Color.White,  
                    fontSize = 14.sp,  
                    textAlign = TextAlign.Center  
                )  
            }  
        }  
    }  
}  
  
// Usage example  
@Composable  
fun CustomToastDemo() {  
    val showToast = remember { mutableStateOf(false) }  
    val toastMessage = remember { mutableStateOf("") }  
      
    Box(modifier = Modifier.fillMaxSize()) {  
        Button(  
            onClick = {  
                toastMessage.value = "This is a custom Compose Toast!"  
                showToast.value = true  
            },  
            modifier = Modifier.align(Alignment.Center)  
        ) {  
            Text("Show Custom Toast")  
        }  
          
        if (showToast.value) {  
            ComposeToast(  
                message = toastMessage.value,  
                duration = 2000L  
            )  
              
            // Reset the state after showing  
            LaunchedEffect(key1 = Unit) {  
                delay(2300L) // slightly longer than the toast duration  
                showToast.value = false  
            }  
        }  
    }  
}  

Toast vs. Snackbar: When to Use Each

While Toasts provide simple feedback, Snackbars offer more features. Here's a comparison to help you choose:

FeatureToastSnackbar
User ActionNo action requiredCan include an action button
PositioningPrimarily bottom of screen, customizableTypically bottom of screen
DurationFixed durations (SHORT, LONG)More flexible duration control
DismissalAuto-dismissal onlyCan be swiped away or dismissed by action
IntegrationAndroid framework componentMaterial Design component
StackingMultiple toasts queue upOnly one shown at a time
Compose ImplementationRequires contextNative Compose implementation available