DEV Community

Nadeem Iqbal
Nadeem Iqbal

Posted on

Frosted glass for Compose Multiplatform without OOMing on low-end Android

liquid-glass demo: frosted glass surfaces with the quality-tier picker over a colorful backdrop

What this is

liquid-glass is a small Compose Multiplatform library that gives you iOS 26-style frosted backdrop blur. It ships a Modifier.liquidGlass() plus three composables: GlassCard, GlassButton, and GlassNavBar. Same code runs on Android, iOS, Desktop, and Web.

Why I built it

Compose's built-in Modifier.blur blurs a composable's own content, not the backdrop behind it. Chris Banes's haze library solves the backdrop-blur problem cleanly and I'd happily recommend it. The remaining gap, for me, was graceful degradation. The iOS 26 "liquid glass" effect is heavy enough that Apple itself disables it on older hardware. On Android the same effect can chew through GPU memory on a 2GB device. I wanted a single composable I could drop in without writing per-device branching every time.

How it works

Three explicit quality tiers, auto-picked by platform:

Tier Blur radius Saturation Backdrop layer Auto-picked on
Full 24.dp 1.4x Full-res Android 12+ (non-low-RAM), iOS 17+, Desktop, Web
Medium 16.dp 1.2x 0.5x downsampled iOS 15 to 16 (opt-in elsewhere)
Fallback 0.dp 1.0x None, zero alloc Android < 12 or isLowRamDevice, iOS < 15

The Fallback tier is the part I care about most. It allocates zero offscreen buffers and skips the blur entirely. The same code that draws frosted glass on a Pixel 9 quietly draws a flat tint with an edge sheen on a 2GB Android 11 device, without an OOM.

The composables consume the auto-detected tier through a LiquidGlassState:

@Composable
fun Screen() {
    val state = rememberLiquidGlassState()  // auto-picks per device

    Box(Modifier.fillMaxSize()) {
        // 1) Anything inside this box becomes the backdrop the glass samples from.
        Image(
            painter = painterResource(R.drawable.scenery),
            contentDescription = null,
            contentScale = ContentScale.Crop,
            modifier = Modifier.fillMaxSize().liquidGlassSource(state),
        )

        // 2) A floating glass card on top, sampling the backdrop above.
        GlassCard(
            state = state,
            modifier = Modifier.align(Alignment.Center).padding(24.dp),
        ) {
            Text("Frosted, light-refracting surface, drop-in")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

You can force a specific tier (for a brand-mandated "Full everywhere" look) or downgrade for low-end shells:

val state = rememberLiquidGlassState(LiquidGlassQuality.Full)
val state = rememberLiquidGlassState(LiquidGlassQuality.Fallback)
Enter fullscreen mode Exit fullscreen mode

What it isn't

It's 0.1.0. There's no GlassDialog or GlassBottomSheet Material 3 wrapper yet, no dynamic-color edge sheen sampled from the captured backdrop, and no Sk SL refraction shader. Those are on the roadmap. If you need any of those today, haze is more mature and very flexible.

Try it

// gradle/libs.versions.toml
[libraries]
liquid-glass = { module = "io.github.nadeemiqbal:liquid-glass", version = "0.1.0" }

// commonMain dependencies
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation(libs.liquid.glass)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Links

Repo: https://github.com/NadeemIqbal/liquid-glass
Maven Central: https://central.sonatype.com/artifact/io.github.nadeemiqbal/liquid-glass

Top comments (0)