A lightweight, reusable UI component built with Jetpack Compose Multiplatform for displaying beautiful and responsive empty states across Android, Desktop, and Web platforms.
- An empty state is a UI design pattern used when there's no content to display, such as no internet connection, empty search results, or first-time app usage.
- It typically includes an illustration, a title, a subtitle explaining the situation, and an optional call-to-action button (e.g., retry).
- Purpose: Guides users, reduces frustration, and encourages next steps. Improves UX by making "nothing" informative and engaging.
- Cross-platform support (Android / Desktop / Web)
- Lightweight and customizable
- Plug-and-play empty UI screens
- Responsive design out-of-the-box
- Optional icon, title, description, and action button
- Explore the full UI experience in our Compose UI Showcase App
- Watch the tutorial on YouTube: Compose Multiplatform Empty State Preview
For the full source code, check the files in this repository (e.g., NoInternetScreen.kt). You can clone and run the project to test it directly.
Here's a key snippet of the main composable function:
@Composable
fun NoInternetScreen(
    title: String = stringResource(Res.string.no_internet_title),
    subtitle: String = stringResource(Res.string.no_internet_subtitle),
    imageRes: Painter = painterResource(Res.drawable.empty_state_no_internet_red),
    modifier: Modifier = Modifier,
    onRetry: () -> Unit = {}
) {
    val (alphaAnim, scaleAnim) = animateFadeAndScale()
    BoxWithConstraints(
        modifier = modifier
            .fillMaxSize()
            .background(MaterialTheme.colorScheme.background)
            .padding(NoInternetConstants.PADDING)
    ) {
        val isLandscape = maxWidth > maxHeight
        val layoutModifier = Modifier
            .fillMaxSize()
            .alpha(alphaAnim)
            .scale(scaleAnim)
        if (isLandscape) {
            Row(
                modifier = layoutModifier,
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                ImageSection(imageRes)
                TextSection(title, subtitle, onRetry)
            }
        } else {
            Column(
                modifier = layoutModifier,
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                ImageSection(imageRes)
                Spacer(modifier = Modifier.height(NoInternetConstants.TEXT_SPACING * 2))
                TextSection(title, subtitle, onRetry)
            }
        }
    }
}To use the NoInternetScreen in your project, call the composable function:
NoInternetScreen(
    onRetry = { /* Handle retry action */ }
)Customize as needed by passing title, subtitle, image, or modifier.
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
