Building Grid Layouts in HarmonyOS with Grid and GridItem

To create responsive grid layouts in HarmonyOS, developers use the Grid container along with GridItem children. This approach supports flexible sizing, spacing, direction control, and even pagination.

Defining Rows and Columns with Templates

The structure of a grid is defined using rowsTemplate and columnsTemplate, which accept CSS-like fraction units (fr). Gaps between cells are controlled via rowsGap and columnsGap.

@Entry
@Component
struct GridLayoutExample {
  build() {
    Column() {
      Grid() {
        [1, 2, 3, 4, 5, 6, 7, 8, 9].map((num) => {
          return (
            <GridItem>
              <Text>{num.toString()}</Text>
                .backgroundColor(num % 4 === 0 ? Color.Yellow : 
                                num % 3 === 0 ? Color.Gray :
                                num % 2 === 0 ? Color.Pink : Color.Orange)
                .width('100%')
                .height('100%')
            </GridItem>
          );
        })
      }
      .rowsTemplate('1fr 1fr 1fr')
      .columnsTemplate('1fr 2fr 1fr')
      .columnsGap(15)
      .rowsGap(10)
      .height(200)
    }
    .width('100%')
  }
}

Controlling Layout Direction and Item Limits

When rowsTemplate or columnsTemplate is specified, properties like layoutDirection, maxCount, and minCount are ignored. However, without templates, you can define how items flow:

  • GridDirection.Row: Items fill rows left-to-right before wrapping.
  • GridDirection.Column: Items fill columns top-to-bottom before moving right.
@Entry
@Component
struct DirectionalGrid {
  private items: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9];

  build() {
    Column() {
      Grid() {
        ForEach(this.items, (item: number) => {
          GridItem() {
            Text(item.toString())
              .backgroundColor(item % 4 === 0 ? Color.Yellow : 
                              item % 3 === 0 ? Color.Green :
                              item % 2 === 0 ? Color.Pink : Color.Orange)
              .width('20%')
              .height('20%')
          }
        }, (item: number) => item.toString())
      }
      .maxCount(3)
      .layoutDirection(GridDirection.Row)
      .columnsGap(15)
      .rowsGap(10)
      .height(300)
    }
    .width('100%')
    .backgroundColor(Color.Grey)
  }
}

Dynamic Grids Using ForEach

For dynamic content, use ForEach to render GridItem components from a array. This ensures efficient rendering and proper key management.

@Entry
@Component
struct DynamicGrid {
  @State data: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];

  build() {
    Column() {
      Grid() {
        ForEach(this.data, (val: string) => {
          GridItem() {
            Text(val)
              .backgroundColor(Color.Orange)
              .textAlign(TextAlign.Center)
              .width('100%')
              .height('100%')
          }
        }, (val: string) => val)
      }
      .maxCount(3)
      .layoutDirection(GridDirection.Column)
      .columnsGap(15)
      .rowsGap(10)
      .height(300)
    }
    .width('100%')
    .backgroundColor(Color.Grey)
  }
}

Scrollable Grid Behavior

The scroll direction depends on which template is used:

  • Specifying columnsTemplate enables vertical scrolling.
  • Specifying rowsTemplate enables horizontal scrolling.
@Entry
@Component
struct ScrollableGrid {
  @State labels: string[] = ['X', 'Y', 'Z', 'W', 'V', 'U', 'T', 'S', 'R'];

  build() {
    Column() {
      Grid() {
        ForEach(this.labels, (label: string) => {
          GridItem() {
            Text(label)
              .backgroundColor(Color.Orange)
              .width('100%')
              .height('100%')
          }
          .width('25%')
          .backgroundColor(Color.Pink)
          .border({ width: 1, style: BorderStyle.Dashed })
        }, (label: string) => label)
      }
      .rowsTemplate('1fr 1fr') // → horizontal scroll
      .columnsGap(15)
      .rowsGap(10)
      .height(200)
    }
    .width('100%')
    .backgroundColor(Color.Grey)
  }
}

Implementing Page-by-Page Navigation with Scroller

Attach a Scroller instance to enable programmatic scrolling. Use scrollPage() to navigate between pages based on the current layout orientation.

@Entry
@Component
struct PagedGrid {
  @State entries: string[] = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6'];
  private pager: Scroller = new Scroller();

  build() {
    Column() {
      Grid(this.pager) {
        ForEach(this.entries, (entry: string) => {
          GridItem() {
            Text(entry)
              .backgroundColor(Color.Orange)
              .textAlign(TextAlign.Center)
              .width('100%')
              .height('100%')
          }
          .width('50%')
          .backgroundColor(Color.Pink)
          .border({ width: 1, style: BorderStyle.Dashed })
        }, (entry: string) => entry)
      }
      .columnsTemplate('1fr 1fr') // vertical paging
      .columnsGap(15)
      .rowsGap(10)
      .height(150)

      Row({ space: 20 }) {
        Button('Previous')
          .onClick(() => this.pager.scrollPage({ next: false }))

        Button('Next')
          .onClick(() => this.pager.scrollPage({ next: true }))
      }
    }
    .width('100%')
    .backgroundColor(Color.Grey)
  }
}

Tags: HarmonyOS ArkTS Grid Layout UI Development Scroller

Posted on Wed, 01 Jul 2026 17:59:05 +0000 by aka_bigred