Sitemap

Nested Scroll in Jetpack Compose: The Forbidden Curse (and How I Broke It)

3 min readJul 7, 2025

⚠️ Any Compose developer knows: having a scrollable container inside a scrollable container is a terrible idea.
Why?
Because it crashes. Spectacularly. 💥

Press enter or click to view image in full size

You’ll get something like this in your logs:

Vertically scrollable component was measured with an 
infinity maximum height constraints, which is disallowed.
One of the common reasons is nesting layouts like
LazyColumn and Column(Modifier.verticalScroll()).

🕵️‍♂️ The Problem I Faced

Recently, I had a case where I had to put a LazyColumn inside a Scrollable Column.
And of course… putting it directly would lead to a crash. 😬

But I did what any stubborn developer would do —
Face the problem head on even after knowing there’s no solution.

(Maybe it’s just me and you’re all normal people. 😅)

🔍 Looking into the Logs

While peeking at the crash logs 📝, it became obvious:

Issue:

Maximum height is going infinite ♾️.

Solution:
👉 Just set the max height.

And boom — the curse is lifted. ✨

😏 But Wait… My Case Was Different

I didn’t want to force my users to manually set a max height on every LazyColumn they used.
That’s just a chore. 🥱

Compose engineers had good reasons for this limitation, but I wanted to be a bit more… clever about it.

What if the LazyColumn (or a Scrollable Column for that matter) worked safely, whether or not the user supplied a max height?

🪄 The Algorithm (It’s Simpler Than You Think)

if (crash_going_to_happen)
don’t.

Yup, that’s it.

💡 The Modifier Hack That Saved the Day

I wrote a custom modifier to safely handle nested scroll crashes:

fun Modifier.disableNestedScrollCrash(): Modifier {
return this.then(
Modifier
.layout { measurable, constraints ->
val safeConstraints = if(constraints.maxHeight == Int.MAX_VALUE) {
constraints.copy(maxHeight = YOUR_MAX_HEIGHT_VALUE)
} else {
constraints
}
val placeable = measurable.measure(safeConstraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
)
}

📌 Note:

  • YOUR_MAX_HEIGHT_VALUE can be whatever you want. I personally use Screen height as my max value.
  • Just don’t make it too big — remember (Not a compose pun), in worst cases this will become the actual height of your LazyColumn 📏.
  • The more height you give, the less lazy your lazy column will be.

✅ For nested scrolling in width, swap height variables with width.

📸 Illustration of the Concept:

Press enter or click to view image in full size

📝 One More Thing!

This modifier trick isn’t just for LazyColumn inside ScrollView.
You can use it for any composable with a scrollable modifier too.

📌 But like all modifier chaining rules in Compose — placement matters!

❌ Incorrect:

Modifier
.verticalScroll(scrollState)
.disableNestedScrollCrash()

👆 Problem:
This applies the max height constraint after the scroll modifier.
Meaning if your scrollable content is, say 3000px, and you cap it at 500px here — it’ll clip your content to 500px with no way to scroll the other 2500px.

✅ Correct:

Modifier
.disableNestedScrollCrash()
.verticalScroll(scrollState)

👆 This is the right way.
Now the modifier sets a safe max height on the container, then the scroll modifier kicks in — allowing you to scroll the rest of the content smoothly.

🎉 That’s It!

I know it’s an unconventional solution to a niche issue —
but hey, if it works, it works. 👏

If you ever run into this, feel free to copy this trick and make your Compose layouts a little safer and lazier 😎.

☕ Enjoying the content? Buy me a coffee to keep the ideas flowing!

--

--

Abhilash
Abhilash

Written by Abhilash

Android Developer. Kotlin Lover, Compose Enthusiast. Works at Zoho.

No responses yet