100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Kotlin

Layouts: Row, Column, and Box

Row, Column, and Box are Compose's three foundational layout composables for arranging children horizontally, vertically, or stacked, forming the basis of nearly every screen.

Building UIs with ComposeBeginner8 min readJul 8, 2026
Analogies

Layouts: Row, Column, and Box

Almost every Compose screen is built from three foundational layout composables: Row arranges children horizontally, Column arranges children vertically, and Box stacks children on top of one another (z-axis). Each accepts arrangement and alignment parameters that control spacing and positioning of children along and across the main axis, plus a content lambda where child composables are declared.

🏏

Cricket analogy: A cricket field diagram lines fielders horizontally along the boundary rope (Row), stacks batting order vertically on the scoreboard (Column), or overlays the fielding heat map on top of the pitch map (Box) — three fundamentally different ways to arrange the same information.

Arrangement and Alignment

Row and Column take a horizontalArrangement/verticalArrangement parameter (how children are spaced along the main axis — e.g. Arrangement.SpaceBetween, Arrangement.Center) and a verticalAlignment/horizontalAlignment parameter (how children align on the cross axis — e.g. Alignment.CenterVertically). Box instead uses a single contentAlignment parameter, since all children share the same stacking area, and individual children can override their own position with Modifier.align(...).

🏏

Cricket analogy: Spacing fielders evenly around the boundary with equal gaps between each (Arrangement.SpaceBetween) while keeping them all aligned at the same distance from the rope (CenterVertically-equivalent) shows how Row's two independent axis parameters control spacing and alignment separately.

kotlin
@Composable
fun ProductCard(name: String, price: String, imageRes: Int) {
    Box(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(4.dp)
        ) {
            Image(
                painter = painterResource(imageRes),
                contentDescription = name,
                modifier = Modifier.size(120.dp)
            )
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(text = name, style = MaterialTheme.typography.titleSmall)
                Text(text = price, style = MaterialTheme.typography.labelLarge)
            }
        }
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = "Favorite",
            modifier = Modifier.align(Alignment.TopEnd).padding(8.dp)
        )
    }
}

Weight and Flexible Sizing

Inside a Row or Column, Modifier.weight(1f) makes a child fill remaining available space proportionally relative to sibling weights — the direct equivalent of layout_weight in the old LinearLayout. Weight is a RowScope/ColumnScope-specific modifier, meaning it's only available on direct children of a Row or Column, enforced by Kotlin's scoped extension functions.

🏏

Cricket analogy: In a scorecard's partnership summary, if two batsmen's contributions are shown as proportional bars, giving one batsman Modifier.weight(2f) and the other weight(1f) makes the higher scorer's bar take twice the width — but this weighting only works because both bars sit inside the same Row (innings summary).

Row, Column, and Box are themselves built on top of Compose's lower-level Layout composable, the same primitive available for writing fully custom layout logic — they're not 'magic,' just well-designed convenience wrappers.

A common bug is nesting a scrollable Column inside another scrollable Column (or a LazyColumn inside a Column with vertical scroll) which causes an 'unbounded height' crash — Compose can't measure infinite height inside infinite height. Use LazyColumn for large/scrollable lists instead of a scrollable Column with many children.

  • Row arranges children horizontally, Column vertically, Box stacks children by z-order.
  • Arrangement controls spacing along the main axis; alignment controls the cross axis.
  • Box uses contentAlignment plus per-child Modifier.align() for stacking control.
  • Modifier.weight(1f) distributes remaining space proportionally among Row/Column children.
  • weight is scoped to RowScope/ColumnScope and only applies to direct children.
  • Row/Column/Box are convenience wrappers around the lower-level Layout composable.

Practice what you learned

Was this page helpful?

Topics covered

#Kotlin#AndroidWithJetpackComposeStudyNotes#MobileDevelopment#LayoutsRowColumnAndBox#Layouts#Row#Column#Box#StudyNotes#SkillVeris