Automatically switching from horizontal to vertical layout
Recently, I came across a requirement where I needed to display two horizontal buttons inside a box. However, if the text of any button overflows (i.e., it doesn’t fit in the available space), the layout should automatically switch to a vertical format.
So, the key question is:
How do we detect if any of the button texts are overflowing?

In this blog, I’ll walk you through the process of detecting text overflow in Jetpack Compose buttons and dynamically switching between horizontal and vertical layouts.
To solve this, I created a custom composable called OverflowAwareButton
using the TextLayoutResult.hasVisualOverflow
Text property. This boolean flag becomes true
when the text doesn’t fit in the given constraints (e.g., a single line).
I then passed this result upward via a callback, allowing the parent composable to decide whether to render the buttons in a Row
(horizontal) or a Column
(vertical) format based on overflow status.
Here’s a simplified example of how the callback and layout switch work
@Composable | |
fun OverflowAwareButton( | |
text: String, | |
onTextOverflow: (Boolean) -> Unit | |
) { | |
Button(onClick = {}) { | |
Text( | |
text = text, | |
maxLines = 1, | |
overflow = TextOverflow.Ellipsis, | |
onTextLayout = { textLayoutResult -> | |
onTextOverflow(textLayoutResult.hasVisualOverflow) | |
} | |
) | |
} | |
} |
Created a horizontal box with overflow-aware buttons to detect text overflow in horizontal mode and a vertical box with buttons for layout switching when overflow occurs.
@Composable | |
fun HorizontalBox(onTextOverflow: (Boolean) -> Unit) { | |
Row { | |
OverflowAwareButton(text = "Very long text that might overflow", onTextOverflow = onTextOverflow) | |
OverflowAwareButton(text = "Another Button", onTextOverflow = onTextOverflow) | |
} | |
} | |
@Composable | |
fun VerticalBox() { | |
Column { | |
Button(onClick = {}) { | |
Text( | |
text = "Very long text that might overflow", | |
maxLines = 1, | |
overflow = TextOverflow.Ellipsis, | |
) | |
} | |
Button(onClick = {}) { | |
Text( | |
text = "Another Button", | |
maxLines = 1, | |
overflow = TextOverflow.Ellipsis, | |
) | |
} | |
} | |
} |
Created a DynamicBoxWithButton
layout that uses a mutable isOverflowing
variable to switch between horizontal and vertical button arrangements. The variable is mutable because the UI needs to react and recompose dynamically when the overflow state changes.
@Composable | |
fun DynamicBoxWithButton() { | |
var isOverflowing by remember { mutableStateOf(false) } | |
if (isOverflowing) { | |
VerticalBox() | |
} else { | |
HorizontalBox(onTextOverflow = { isOverflowing = it }) | |
} | |
} |
Job Offers
That’s it, folks! Thanks for reading. Feel free to try out the solution above, and if you come up with a better one, I’d love to hear it in the comments. Always happy to learn and improve!
Found this article useful? Follow me (Suchi Bansal) on Medium, and check out my other popular articles below!
Make Android apps more accessible to all
This article was previously published on proandroiddev.com.