A lightweight, state-driven library for Jetpack Compose that makes showing toast messages, snackbars, and dialogs simple and intuitive. It provides a clean, declarative API that integrates seamlessly with Compose's reactive paradigm.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}implementation("com.github.zahid4kh:compose-alert-kit:1.0.0")Add the dependency to your project's app level build.gradle.kts file:
implementation("io.github.zahid4kh:compose-alert-kit:1.0.0")- π Composable API - Fully integrated with Jetpack Compose's lifecycle
- π§ State-driven - Uses Compose state to trigger messages naturally
- π« No duplicates - Automatically cancels previous messages when showing new ones
- π Context-aware - Automatically retrieves the current context
- π§© Simple integration - Just a single line of code to get started
Toastify provides a simple way to show Android Toast messages in a Compose-friendly way.
πΉ See it in action: Check out the recordings for video demonstrations of Toastify.
@Composable
fun MyScreen() {
// Create a toast state that manages showing toasts
val toastifyState = rememberToastify()
Button(onClick = {
toastifyState.show("Button clicked!")
}) {
Text("Click Me")
}
}Button(onClick = {
toastifyState.show("This is a long toast", Toast.LENGTH_LONG)
} ) {
Text("Show Long Toast")
}Snackify provides a state-driven approach to showing Material 3 Snackbars.
πΉ See it in action: Check out the recordings for video demonstrations of Snackify.
There are two ways to use Snackify, depending on your needs:
- Create both SnackbarHostState and SnackifyState at once:
@Composable
fun MyScreen() {
val (snackbarHostState, snackifyState) = rememberSnackify()
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
) { padding ->
Column(modifier = Modifier.padding(padding)) {
Button(onClick = {
snackifyState.show("This is a snackbar")
}) {
Text("Show Snackbar")
}
}
}
}- Use an existing SnackbarHostState:
@Composable
fun MyApp() {
// Create a shared SnackbarHostState for the entire app
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(snackbarHost = { SnackbarHost(hostState = snackbarHostState) }) { padding ->
// Content
}
}
@Composable
fun SomeScreen(snackbarHostState: SnackbarHostState) {
// Create a SnackifyState connected to the existing host state
val snackifyState = rememberSnackify(snackbarHostState)
Button(onClick = {
snackifyState.show("Screen-specific message")
}) {
Text("Show Snackbar")
}
}You can customize snackbars with actions, duration, and callbacks:
snackifyState.show(
message = "Item deleted",
actionLabel = "Undo",
duration = SnackbarDuration.Long,
onAction = { /* Restore the item */ },
onDismiss = { /* Clean up */ }
)Button(onClick = {
snackifyState.dismiss()
}) {
Text("Dismiss Snackbar")
}The library provides a set of ready-to-use dialog components for common use cases, all with a consistent API and styling.
πΉ See it in action: Check out the recordings for video demonstrations of all dialog components.
A dialog that automatically dismisses after a specified duration, perfect for brief notifications.
var showFlashDialog by remember { mutableStateOf(false) }
Button(onClick = { showFlashDialog = true }) {
Text("Show Flash Dialog")
}
FlashDialog(
visible = showFlashDialog,
message = "This is a flash message",
icon = {
Icon(Icons.Default.Info, contentDescription = "Info")
},
duration = 1500,
onDismiss = { showFlashDialog = false }
)A dialog for showing success messages that auto-dismisses after a short duration.
var showSuccessDialog by remember { mutableStateOf(false) }
Button(onClick = { showSuccessDialog = true }) {
Text("Show Success Dialog")
}
SuccessDialog(
visible = showSuccessDialog,
message = "Operation completed successfully!",
onDismiss = { showSuccessDialog = false }
)A dialog for displaying error messages with a prominent error icon and dismiss button.
var showErrorDialog by remember { mutableStateOf(false) }
Button(onClick = { showErrorDialog = true }) {
Text("Show Error Dialog")
}
ErrorDialog(
visible = showErrorDialog,
title = "Error Occurred",
message = "Something went wrong while processing your request.",
onDismiss = { showErrorDialog = false }
)A dialog for showing warning messages with appropriate icon and confirmation.
var showWarningDialog by remember { mutableStateOf(false) }
Button(onClick = { showWarningDialog = true }) {
Text("Show Warning Dialog")
}
WarningDialog(
visible = showWarningDialog,
title = "Warning",
message = "This action might have unexpected consequences.",
onDismiss = { showWarningDialog = false }
)A dialog for asking users to confirm important actions with confirm and cancel options.
var showConfirmationDialog by remember { mutableStateOf(false) }
val toastifyState = rememberToastify()
Button(onClick = { showConfirmationDialog = true }) {
Text("Show Confirmation Dialog")
}
ConfirmationDialog(
visible = showConfirmationDialog,
title = "Confirm Action",
message = "Are you sure you want to proceed with this action?",
onConfirm = {
toastifyState.show("Action confirmed")
},
onDismiss = { showConfirmationDialog = false }
)A dialog showing a progress indicator while an operation is in progress.
var showLoadingDialog by remember { mutableStateOf(false) }
var isLoading by remember { mutableStateOf(false) }
Button(onClick = {
if (!isLoading) {
isLoading = true
showLoadingDialog = true
// Simulate process completion
Handler(Looper.getMainLooper()).postDelayed({
showLoadingDialog = false
isLoading = false
}, 3000)
}
}) {
Text(if (!isLoading) "Show Loading Dialog" else "Loading...")
}
LoadingDialog(
visible = showLoadingDialog,
message = "Processing your request...",
onDismiss = {
showLoadingDialog = false
isLoading = false
}
)A dialog with a text input field for capturing user input.
var showInputDialog by remember { mutableStateOf(false) }
val toastifyState = rememberToastify()
Button(onClick = { showInputDialog = true }) {
Text("Show Input Dialog")
}
InputDialog(
visible = showInputDialog,
title = "Enter Information",
placeholder = "Type something here",
keyboardType = KeyboardType.Text,
onConfirm = { input ->
toastifyState.show("You entered: $input")
},
onDismiss = { showInputDialog = false }
)Don't do this:
// This won't work! The toast will never show.
ToastifyState().show("This won't be visible")Why it fails: The state needs to be remembered by Compose and connected to a LaunchedEffect that actually shows the toast/snackbar. Direct instantiation bypasses this mechanism.
Do this instead:
val toastifyState = rememberToastify()
toastifyState.show("This will work correctly")Don't do this:
@Composable
fun MyApp() {
val toastifyState = rememberToastify()
LaunchedEffect(Unit) {
// This toast will only show once when the composition starts
toastifyState.show("App started")
}
}Do this instead:
@Composable
fun MyApp() {
val toastifyState = rememberToastify()
var isFirstLaunch by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
if (isFirstLaunch) {
toastifyState.show("App started")
isFirstLaunch = false
}
}
}Copyright 2025 Zahid
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.






