Nested Scroll in Jetpack Compose: The Forbidden Curse (and How I Broke It)
⚠️ Any Compose developer knows: having a scrollable container inside a scrollable container is a terrible idea.
Why?
Because it crashes. Spectacularly. 💥
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_VALUEcan 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:
📝 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!
