Column: vertical arrangement and container configuration in Compose

Author: IT Sectr Published: 2026-06-28 Reading time: 8 min

Column is a built-in Composable component of Jetpack Compose from the compose.foundation.layout package that arranges child elements vertically, one below another. Column is the equivalent of LinearLayout with vertical orientation from the old View system, but unlike it, uses a declarative description and automatically reacts to state changes. According to Google Android Developers, 2026, Column is one of the three basic containers along with Row and Box.

Key Takeaways

  • Column arranges elements vertically with Arrangement and Alignment configuration
  • Arrangement defines how space is distributed between elements vertically
  • Alignment sets horizontal alignment of each element inside Column
  • Weight distributes free space proportionally between elements
  • IntrinsicSize allows Column to adjust its size to the child's min/max width

What is Column in Jetpack Compose

Column is a Composable function that accepts optional parameters: modifier, verticalArrangement, horizontalAlignment, and content — a lambda with ColumnScope. Inside Column, child Composable functions are arranged from top to bottom in declaration order. The height of Column equals the sum of child heights plus the space specified by Arrangement. The width equals the maximum child width considering Alignment.

Column is an invisible container: it has no background or border by default. If you need a background, add Modifier.background() to the Column itself. Unlike LazyColumn, Column renders all child elements simultaneously and does not support virtualization. This means Column is only suitable for small data sets — up to 10-15 elements. For long lists, use LazyColumn.

ColumnScope is the receiver for the content lambda of Column. It provides additional modifiers that only work inside Column: weight(), align(), alignByBaseline(). These modifiers have no meaning outside Column because they rely on vertical layout specifics. For example, Modifier.align(Alignment.CenterHorizontally) aligns a child element to the center of the Column horizontally.

Column parameters: Arrangement, Alignment, Modifier

VerticalArrangement determines how vertical space is distributed between elements. Available values: Arrangement.Top (default), Bottom, Center, SpaceBetween, SpaceEvenly, SpaceAround. If the Column height is greater than the sum of element heights, Arrangement distributes the free space. If elements take up the full height, Arrangement has no effect.

HorizontalAlignment sets the horizontal alignment of each child element. Alignment.Start (default for LTR), CenterHorizontally, End. Alignment acts on each element independently: if one element is narrow and another is wide, the first one will be aligned, the second may extend beyond Column boundaries. Alignment only works if Column has a fixed width or fillMaxWidth.

Modifier for Column: Column accepts a Modifier that applies to the container itself. Modifier.fillMaxWidth(), fillMaxHeight(), size(), padding() — all standard modifiers work. Special note: Modifier.height(IntrinsicSize.Min) forces Column to calculate the minimum height based on child elements using Intrinsic measurement.

kotlin
@Composable
fun ColumnArrangementDemo() {
    Column(
        modifier = Modifier.fillMaxSize().background(Color(0xFFF5F5F5)),
        verticalArrangement = Arrangement.SpaceEvenly,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Top", modifier = Modifier.background(Color.Cyan))
        Text("Middle", modifier = Modifier.background(Color.Magenta))
        Text("Bottom", modifier = Modifier.background(Color.Yellow))
    }
}

    // IntrinsicSize: Column adjusts height to content
@Composable
fun IntrinsicColumn() {
    Column(
        modifier = Modifier
            .height(IntrinsicSize.Min)
            .width(200.dp)
    ) {
        Text("Short text")
        Text("A very long text that will wrap inside the column")
    }
}
ArrangementBehavior
Arrangement.TopElements are pushed to the top, free space at the bottom
Arrangement.CenterElements are centered, space is split equally above and below
Arrangement.SpaceBetweenFirst element at top, last at bottom, others evenly spaced
Arrangement.SpaceEvenlyEqual gaps between all elements and edges
Arrangement.SpaceAroundEqual gaps between elements, half gaps at edges

Column weight: distributing space between elements

Modifier.weight() is a ColumnScope modifier that distributes free vertical space between Column elements proportionally to the specified weights. If Column occupies 400dp height and child elements total 100dp, the remaining 300dp are split among weight elements. An element with weight(2f) gets twice as much space as an element with weight(1f).

fill — the second parameter of weight: weight(weight: Float, fill: Boolean = true). If fill = true (default), the element stretches to the full available height. If fill = false, the element only takes its intrinsic height, and the remaining space stays empty. This is useful when an element should be pushed to one side but weight only defines the proportion of empty space distribution.

Weight limitations: weight only works in Column with a fixed height or fillMaxHeight(). If the Column height is determined by child elements (wrap content), weights have no meaning — there is no free space to distribute. Also, weight cannot be combined with Modifier.height() on the same element — they conflict, and weight is ignored.

kotlin
@Composable
fun WeightedColumn() {
    Column(
        modifier = Modifier.fillMaxHeight().width(300.dp)
    ) {
        // Takes 1/6 of height (weight 1 of sum 1+2+3=6)
        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
                .background(Color.Red)
        )
        // Takes 2/6 of height
        Box(
            modifier = Modifier
                .weight(2f)
                .fillMaxWidth()
                .background(Color.Green)
        )
        // Takes 3/6 of height
        Box(
            modifier = Modifier
                .weight(3f)
                .fillMaxWidth()
                .background(Color.Blue)
        )
    }
}

Column vs LazyColumn: when to use what

Column renders all child elements immediately. If there are more than 10-15 elements, Column creates significant composition and measurement overhead. LazyColumn, on the other hand, only renders visible elements and reuses invisible ones. For long lists, lists with thousands of elements, infinite lists, or chats — LazyColumn is mandatory.

When Column is better: form screens (3-10 fields), profile cards, vertical columns with icons, menus. Column also supports IntrinsicSize, which is useful for adaptive height. Additionally, Column is easier to debug — no virtualization, all elements are visible in Layout Inspector. For static UI, Column is the right choice.

LazyColumn provides: item caching, key-based identity, add/remove animation (animateItemPlacement), sticky headers. If the list contains elements of different types (different viewTypes), use LazyColumn with a sealed class in items. Column does not support sticky headers (they need to be emulated via scrollable Column). Also, LazyColumn supports LazyVerticalGrid when using GridCells.

CriterionColumnLazyColumn
Number of elementsUp to 10-15Any
PerformanceAlways renders allOnly visible + buffer
ScrollingVia Modifier.verticalScrollBuilt-in
IntrinsicSizeSupportsDoes not support
Sticky headersNo (emulation)Yes (stickyHeader)
Element animationNo built-inanimateItemPlacement

Practical examples of using Column

Let's look at a user profile screen where Column is used as the main container for the avatar, name, bio, and action buttons. Here, Column with IntrinsicSize.Min adjusts to the content, and weight is used to distribute space between sections.

kotlin
@Composable
fun UserProfileCard(name: String, bio: String) {
    Card(
        modifier = Modifier.fillMaxWidth().padding(16.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Column(
            modifier = Modifier.fillMaxWidth().padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            // Avatar
            Icon(
                imageVector = Icons.Default.AccountCircle,
                contentDescription = "Avatar",
                modifier = Modifier.size(64.dp)
            )
            // Name
            Text(name, style = MaterialTheme.typography.headlineSmall)
            // Bio
            Text(bio, style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier.padding(top = 4.dp))
            // Action buttons
            Row(
                horizontalArrangement = Arrangement.spacedBy(12.dp),
                modifier = Modifier.padding(top = 12.dp)
            ) {
                Button(onClick = { }) { Text("Message") }
                OutlinedButton(onClick = { }) { Text("Follow") }
            }
        }
    }
}

In the example, Column uses Arrangement.spacedBy(8.dp) for even spacing between elements. horizontalAlignment = CenterHorizontally centers the avatar, name, and bio. The Row inside Column is a nested container for buttons in one row. This combination of Column (vertical layout) and Row (horizontal layout) is a typical UI building pattern in Compose.

Frequently Asked Questions

How does Column differ from LazyColumn in terms of performance?

Column renders all child elements at once, which causes FPS drops with 100+ elements. LazyColumn only renders visible elements plus a buffer (usually 3-5 screens). For static screens with 3-10 elements, Column is faster since there is no virtualization overhead.

How do I make a Column scrollable?

Add Modifier.verticalScroll(rememberScrollState()) to the Column. This makes the Column scrollable but does not provide virtualization — all elements still render at once. For long scrollable lists, use LazyColumn.

Can I nest Row inside Column and Column inside Row?

Yes, nesting Row/Column is common practice. By combining the two containers, you can build complex grids. However, avoid deep nesting (4+ levels) without necessity — it increases the number of LayoutNode measurements and slows down composition.

How do I make all elements in Column the same width?

Use Modifier.fillMaxWidth() on each child element. If Column has Modifier.fillMaxWidth(), all children with fillMaxWidth() will stretch to full width. Alternatively, use Modifier.weight(1f) in ColumnScope if Column is inside a fixed container.

How does spacedBy work in Column?

Arrangement.spacedBy(space) adds a fixed gap between every two adjacent elements. Unlike SpaceBetween/SpaceAround, spacedBy does not stretch elements — the gap is fixed, and the remaining space stays at the end of the Column. spacedBy does not add a gap before the first or after the last element.

Summary

  • Column — a basic vertical Compose container for arranging elements top to bottom
  • Arrangement controls space distribution (Top, Center, SpaceBetween, spacedBy)
  • Alignment sets horizontal alignment of each child element
  • Weight distributes free space proportionally between elements
  • Column vs LazyColumn: Column for 3-10 elements, LazyColumn for long lists
  • IntrinsicSize allows Column to adjust height to the minimum child measurement
  • Recommendation: use spacedBy for gaps between elements instead of padding on each

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also