Implementing Sticky Headers and Grid Lists in Jetpack Compose

This article explains how to implement sticky headers and grid lists in Jetpack Compose, a modern toolkit for building native UI.

Jetpack Compose, Android’s modern toolkit for building native UI, has revolutionized the way developers create user interfaces. With its declarative approach, Compose simplifies UI development, making it more intuitive and efficient. One of the common UI patterns in mobile applications is the use of sticky headers and grid lists. These components are essential for organizing content in a structured and visually appealing manner. In this article, we’ll explore how to implement sticky headers and grid lists in Jetpack Compose, providing you with a comprehensive guide to enhance your app’s UI.

Understanding Sticky Headers and Grid Lists

Before diving into the implementation, let’s first understand what sticky headers and grid lists are and why they are important.

Sticky Headers

Sticky headers are UI elements that remain fixed at the top of a scrolling list or grid while the content beneath them scrolls. They are particularly useful in long lists or grids where users need context about the content they are viewing. For example, in a contacts app, sticky headers can display the alphabet letters, making it easier for users to navigate through the list.

Grid Lists

Grid lists, on the other hand, are used to display items in a grid layout. They are ideal for presenting homogeneous data, such as images, products, or any other content that benefits from a structured grid format. Grid lists provide a visually appealing way to organize content, making it easier for users to scan and interact with the items.

Setting Up Jetpack Compose

Before we start implementing sticky headers and grid lists, ensure that your project is set up to use Jetpack Compose. If you haven’t already, add the necessary dependencies to your build.gradle file:

dependencies {
    implementation "androidx.compose.ui:ui:1.0.0"
    implementation "androidx.compose.foundation:foundation:1.0.0"
    implementation "androidx.compose.material:material:1.0.0"
    implementation "androidx.compose.runtime:runtime:1.0.0"
    implementation "androidx.activity:activity-compose:1.3.0"
}

Sync your project, and you’re ready to start coding with Jetpack Compose.

Implementing a Grid List in Jetpack Compose

Let’s start by implementing a simple grid list. Jetpack Compose provides a LazyVerticalGrid component that makes it easy to create grid layouts.

Step 1: Define the Grid Layout

First, define the grid layout using the GridCells class. You can specify the number of columns or use adaptive sizing to fit the available space.

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun GridListExample(items: List<String>) {
    LazyVerticalGrid(
        columns = GridCells.Fixed(2), // 2 columns
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp)
    ) {
        items(items) { item ->
            GridItem(item)
        }
    }
}

@Composable
fun GridItem(item: String) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1f)
            .padding(8.dp),
        contentAlignment = Alignment.Center
    ) {
        Text(text = item)
    }
}

In this example, we’ve created a LazyVerticalGrid with two columns. The GridItem composable represents each item in the grid, which is a simple Box with a Text component.

Step 2: Use the Grid List in Your UI

Now that we’ve defined the grid list, let’s use it in our UI. Pass a list of items to the GridListExample composable.

@Composable
fun MyApp() {
    val items = List(20) { "Item $it" }
    GridListExample(items)
}

When you run the app, you’ll see a grid list with two columns, each containing a list item.

Implementing Sticky Headers in Jetpack Compose

Now that we have a grid list, let’s add sticky headers to it. Unfortunately, Jetpack Compose does not provide a built-in sticky header component out of the box. However, we can achieve this functionality using the LazyColumn and LazyVerticalStaggeredGrid components along with some custom logic.

Step 1: Define the Data Structure

First, define a data structure that includes both the header and the items. For example, let’s create a Section data class that contains a header and a list of items.

data class Section(
    val header: String,
    val items: List<String>
)

Step 2: Create the Sticky Header Composable

Next, create a composable for the sticky header. This composable will be reused for each section.

@Composable
fun StickyHeader(header: String) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .background(MaterialTheme.colorScheme.primary)
            .padding(16.dp),
        contentAlignment = Alignment.CenterStart
    ) {
        Text(
            text = header,
            color = MaterialTheme.colorScheme.onPrimary,
            style = MaterialTheme.typography.h6
        )
    }
}

Step 3: Implement the Sticky Header Logic

To implement sticky headers, we’ll use a LazyColumn and manually handle the sticky behavior. We’ll use the item and items functions to add headers and items to the list.

@Composable
fun StickyHeaderGridList(sections: List<Section>) {
    val listState = rememberLazyListState()

    LazyColumn(
        state = listState,
        modifier = Modifier.fillMaxSize()
    ) {
        sections.forEach { section ->
            stickyHeader {
                StickyHeader(section.header)
            }
            items(section.items) { item ->
                GridItem(item)
            }
        }
    }
}

In this example, we’ve created a LazyColumn and used the stickyHeader function to add a sticky header for each section. The items function is used to add the items in each section.

Step 4: Use the Sticky Header Grid List in Your UI

Finally, use the StickyHeaderGridList composable in your UI. Pass a list of sections to the composable.

@Composable
fun MyApp() {
    val sections = listOf(
        Section("Header 1", List(10) { "Item $it" }),
        Section("Header 2", List(15) { "Item $it" }),
        Section("Header 3", List(20) { "Item $it" })
    )
    StickyHeaderGridList(sections)
}

When you run the app, you’ll see a grid list with sticky headers. As you scroll through the list, the headers will stick to the top of the screen, providing context for the items below.

Conclusion

Implementing sticky headers and grid lists in Jetpack Compose can significantly enhance the user experience of your app. While Jetpack Compose does not provide built-in support for sticky headers, you can achieve this functionality with a combination of LazyColumn, LazyVerticalGrid, and custom logic. By following the steps outlined In this article, you can create a visually appealing and user-friendly UI that organizes content effectively.

As you continue to explore Jetpack Compose, you’ll discover even more ways to create dynamic and responsive UIs. The declarative nature of Compose makes it easier than ever to experiment with different layouts and components, allowing you to build apps that are both functional and beautiful.


Last modified 08.03.2025: new content (76eea7a)