This content originally appeared on Level Up Coding - Medium and was authored by Rafa

🔥 Intro
Modern apps are no longer just about functionality. Users expect delight, movement, and personality in their interfaces. That’s why expressive UI is becoming a design priority! With Material 3 introducing Expressive APIs, we can bring playful, dynamic, and emotionally engaging components into Jetpack Compose.
In this post, I’ll walk through building a countdown timer with a LinearWavyProgressIndicator using the experimental Material3ExpressiveApi. You’ll see how easy it is to add motion and polish that makes your app stand out.
🛠️ Breaking Down CountdownWavyProgressIndicator
Here’s the full composable I built:
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun CountdownWavyProgressIndicator(timeIsUp: MutableState<Boolean>) {
val totalTime = 7_000L // total countdown time in milliseconds
val animatedProgress = remember { Animatable(1f) }
// Animate the progress from 1f → 0f over totalTime
LaunchedEffect(Unit) {
animatedProgress.animateTo(
targetValue = 0f,
animationSpec = tween(
durationMillis = totalTime.toInt(),
easing = LinearEasing // smooth, linear shrink
)
)
timeIsUp.value = true // flag when countdown finishes
}
LinearWavyProgressIndicator(
progress = { animatedProgress.value },
modifier = Modifier
.fillMaxWidth()
.height(12.dp),
color = WavyProgressIndicatorDefaults.indicatorColor,
trackColor = WavyProgressIndicatorDefaults.trackColor,
stroke = Stroke(width = 12f),
amplitude = WavyProgressIndicatorDefaults.indicatorAmplitude,
wavelength = WavyProgressIndicatorDefaults.LinearDeterminateWavelength,
waveSpeed = WavyProgressIndicatorDefaults.LinearDeterminateWavelength
)
}
🔑 Key Parts Explained
- Experimental Opt-in → @OptIn(ExperimentalMaterial3ExpressiveApi::class) unlocks expressive APIs like LinearWavyProgressIndicator. (Requires the latest Material 3 version.)
- Countdown Logic →
The countdown is driven by an Animatable that smoothly interpolates progress from 1f → 0f over totalTime. - Smooth Animation →
Using Animatable.animateTo ensures the progress bar shrinks smoothly instead of jumping in discrete steps (like a traditional CountDownTimer). - LaunchedEffect Role →
LaunchedEffect(Unit) launches a coroutine tied to the composable’s lifecycle. It runs once when the composable enters the composition, animates the progress, and safely updates timeIsUp.value when finished. If the composable leaves the screen, the coroutine is automatically canceled, preventing memory leaks. - Time-Up Callback →
Once the animation completes, timeIsUp.value is set to true. You can observe this state in your UI to show a “time’s up” dialog. - Expressive Wave Effect →
LinearWavyProgressIndicator adds a wavy, animated effect to the progress bar, making it visually more appealing than a standard LinearProgressIndicator.
✅ Summary
With just a few lines of code, I combined standard Jetpack Compose animation with Material 3’s expressive API to build a countdown that feels alive.
The payoff? A progress indicator that goes beyond function — adding motion, character, and delight to my UI.
👉 In 2025, static UI won’t cut it! Start experimenting with Expressive APIs and make your app stand out.
🗣️: reach out on LinkedIn, X or Insta
Best,
Rafa
Unlocking Expressive UI in Jetpack Compose with ExperimentalMaterial3ExpressiveApi 🚀 was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Rafa

Rafa | Sciencx (2025-09-03T14:27:43+00:00) Unlocking Expressive UI in Jetpack Compose with ExperimentalMaterial3ExpressiveApi. Retrieved from https://www.scien.cx/2025/09/03/unlocking-expressive-ui-in-jetpack-compose-with-experimentalmaterial3expressiveapi/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.