LazyColumn in Jetpack Compose — what it is, properties and how it works

Author: IT Sectr Published: 2026-06-29 Reading time: 11 min

LazyColumn is a composable function in Jetpack Compose for creating vertical lists with lazy loading of elements. Unlike Column, LazyColumn creates and composes only the elements visible on screen, reusing them during scrolling. According to Google Android Documentation, 2025, LazyColumn is the primary tool for displaying large data sets in mobile applications thanks to efficient memory management.

Key Takeaways

  • LazyColumn — a vertical Jetpack Compose list with lazy loading that creates only visible elements and reuses them during scrolling.
  • items accepts a data collection and a factory function to create list items, while item adds single components.
  • LazyListState tracks the scroll position and allows programmatic control of the list via animateScrollToItem and scrollToItem.
  • Sticky headers pin section headers to the top of the list during scrolling using stickyHeader.
  • LazyColumn supports different item types via the contentType parameter to optimize reuse.

What is LazyColumn in Jetpack Compose

LazyColumn is a composable function that implements a vertical scrollable list with lazy loading. Unlike Column, which renders all children at once, LazyColumn creates only elements that fall within the viewport.

The lazy loading mechanism in LazyColumn is based on element reuse: when an element is hidden during scrolling, its composition and layout can be reused for a new displayed element. This saves memory and CPU time, especially on long lists.

According to Android Developers Blog, 2024, LazyColumn can efficiently handle lists of tens of thousands of elements without significant performance degradation. Each element in LazyColumn has a key that helps Compose identify and preserve the element’s state when the list changes.

Basic LazyColumn signature

LazyColumn accepts parameters modifier, state, contentPadding, reverseLayout, verticalArrangement and horizontalAlignment. Content is defined in a lambda block using DSL functions items and item.

kotlin
@Composable
fun SimpleLazyColumn() {
    val itemsList = (1..100).toList()
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        contentPadding = PaddingValues(16.dp)
    ) {
        items(itemsList) { item ->
            Text(text = "Item $item")
        }
    }
}

LazyColumn parameters: items and item

The LazyColumn DSL block provides items and item functions for adding content. items accepts a data collection, a key, and a factory function to create elements. item adds a single static element to the list.

itemsIndexed is a variant of items that passes the element index in addition to the data. This is useful when you need to know the element position without separate calculation. items(size) accepts only the number of elements and a factory without binding to a collection.

The key parameter in items uniquely identifies each element. According to Material Design Guidelines, 2025, keys improve performance when updating and animating elements, as Compose can track the movement or change of a specific element by key.

Example with different element types

The items function with contentType allows LazyColumn to optimize reuse of elements of different types. The example below uses section headers and regular rows in a single list.

kotlin
@Composable
fun MixedItemsList() {
    LazyColumn {
        item {
            Text(
                text = "Header",
                style = MaterialTheme.typography.headlineMedium
            )
        }
        items(
            items = (1..20).toList(),
            key = { it },
            contentType = { "item" }
        ) { item ->
            Text(text = "Row $item")
        }
    }
}

LazyListState and scroll management

LazyListState is a LazyColumn state object that tracks the current scroll position, the first visible element, and the offset. It can be created via rememberLazyListState() and passed to the state parameter of LazyColumn.

LazyListState provides animateScrollToItem and scrollToItem methods for programmatic scrolling to a specific element. animateScrollToItem creates a smooth scroll animation, while scrollToItem scrolls instantly. Both methods require calling within a coroutine in CompositionContext.

According to Android Developers, 2024, LazyListState also contains layoutInfo, which provides information about visible elements — their indices, offsets, and sizes. This is useful for implementing analytics, view tracking, or infinite scrolling.

Example with programmatic scrolling

In this example, LazyColumn is controlled via LazyListState. A button scrolls the list to item with index 50 with a smooth animation.

kotlin
@Composable
fun ScrollableList() {
    val listState = rememberLazyListState()
    val scope = rememberCoroutineScope()

    Column {
        Button(
            onClick = {
                scope.launch {
                    listState.animateScrollToItem(50)
                }
            }
        ) {
            Text("Scroll to 50")
        }

        LazyColumn(state = listState) {
            items((1..100).toList()) { item ->
                Text(
                    text = "Item $item",
                    modifier = Modifier.padding(8.dp)
                )
            }
        }
    }
}

LazyColumn performance optimization

The key performance factor of LazyColumn is proper use of keys. Each element should have a unique stable key via the key parameter. Without keys, Compose cannot correctly reuse elements when data changes, leading to recomposition.

contentType tells LazyColumn which elements have the same layout type. When two elements with the same contentType enter the recycling pool, LazyColumn can reuse their layout without recomposition. According to Android Developers Blog, 2024, contentType improves performance by 30–50% in lists with different element types.

For LazyColumn, it is also important to avoid unstable parameters in factory functions. Each time an element parameter changes, Compose recomposes that element. Using remember and derivedStateOf for stable values reduces the number of recompositions.

Performance factors table

FactorImpactRecommendation
Keys (key)CriticalAlways set a unique stable key for items
contentTypeSignificantSpecify the element type to optimize reuse
Element sizeModerateUse fixed sizes where possible
Nested listsCriticalAvoid LazyColumn inside LazyColumn — use LazyVerticalGrid

Sticky headers and sections in LazyColumn

stickyHeader is a LazyColumn DSL function that pins a section header to the top of the list during scrolling. When the next section reaches the top, its header replaces the current one. This behavior is familiar to users from contact lists and calendars.

stickyHeader accepts a key and a factory function, similar to item. Unlike a regular item, stickyHeader remains visible while scrolling through its section’s content. When a section is fully scrolled, the next section’s header pushes out the previous one.

According to Material Design Guidelines, 2025, sticky headers improve navigation in long lists and reduce cognitive load on the user. To implement a sticky header, simply wrap a section header in stickyHeader at the correct position relative to the items elements.

kotlin
@Composable
fun SectionedList(sections: Map<String, List<String>>) {
    LazyColumn {
        sections.forEach { (header, items) ->
            stickyHeader {
                Text(
                    text = header,
                    modifier = Modifier.background(Color.White)
                        .padding(16.dp)
                )
            }
            items(items) { item ->
                Text(text = item, modifier = Modifier.padding(8.dp))
            }
        }
    }
}

Frequently Asked Questions

How is LazyColumn different from Column in Compose?

Column renders all elements at once and is suitable for lists up to 20–30 elements. LazyColumn creates only visible elements and reuses them during scrolling, allowing you to work with thousands of elements without performance loss.

How to add separators between LazyColumn elements?

Use Arrangement.spacedBy in the verticalArrangement parameter or items functions with a separator via index. For complex separators, add a separate item with Divider() between list elements.

How to update LazyColumn when data changes?

LazyColumn automatically recomposes when the data collection changes, if stable keys are used. Data changes detected via mutableStateListOf or StateFlow cause only the changed elements to redraw.

Can you nest LazyColumn inside LazyColumn?

Direct nesting of LazyColumn inside LazyColumn is not recommended — both have independent scrolling, creating gesture conflicts. Instead, use a regular Column with LazyColumn inside a scrollable Section or LazyVerticalGrid for grids.

How to detect that LazyColumn has scrolled to the end?

Use LazyListState.layoutInfo.visibleItemsInfo and compare the index of the last visible item with the total number of items. For infinite scrolling, track when the last visible item approaches the end of the list.

Summary

  • LazyColumn — a vertical list with lazy loading that creates and reuses only elements in the viewport for efficient work with large data.
  • items and item — DSL functions for adding data collections and single components to LazyColumn with key and contentType support.
  • LazyListState manages the scroll position, providing programmatic navigation via animateScrollToItem and scrollToItem in coroutines.
  • contentType and key — the main performance optimization tools, reducing recomposition and improving element reuse.
  • stickyHeader pins section headers to the top of the list, improving navigation in long lists with grouped data.
  • Arrangement.spacedBy and contentPadding manage spacing between elements and edges of LazyColumn for Material Design compliance.
  • For horizontal lists with lazy loading, use LazyRow, and for grids — LazyVerticalGrid, following the same lazy loading principle.

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