Read the original article:How to open a semi-modal pop-up window by dragging
Requirement Description
How to trigger a half-modal sheet (semi-modal popup) using a drag gesture — for example, pulling upward to reveal a half-modal sheet in a HarmonyOS application.
Background Knowledge
Half-modal transition:
You can bind a half-modal sheet to a component using the bindSheet attribute. When the component is inserted, the size of the half-modal can be defined using either a custom height or the default built-in height. Once triggered (e.g., clicked or dragged), the modal sheet appears.
In addition, the gesture attribute can bind gesture recognition to a component. When a gesture is successfully recognized, the component is notified through event callbacks.
HarmonyOS also allows gesture composition using the GestureGroup() API, supporting sequential, parallel, or exclusive gesture recognition.
Implementation Steps
- Make a Text component draggable by setting the
draggable(true)property. - Use the
bindSheetattribute to bind this component to a half-modal sheet. - Add a gesture listener using the
gestureproperty. - When the user drags the Text component upward, the gesture’s
onActionUpdateevent is triggered. - Inside this event, set the bound sheet’s
isShowattribute totrueto display the half-modal sheet. - Optionally, adjust the sheet height dynamically based on the gesture’s offset.
This allows users to pull up a half-modal sheet using a drag motion instead of a click.
Code Snippet / Configuration
@Entry
@Component
struct SheetTransitionExample {
@State numbers: number[] = []
@State isShow: boolean = false
@State sheetHeight: number = 300;
aboutToAppear() {
for (let i = 1; i <= 11; i++) {
this.numbers.push(i)
}
}
@Builder
myBuilder() {
Column() {
List() {
ForEach(this.numbers, (item: string) => {
ListItem() {
Text(item.toString())
.fontSize(16)
.textAlign(TextAlign.Center)
.size({ height: 20, width: '100%' })
}.margin(10)
.borderRadius(10)
.backgroundColor('#ffdda63b')
}, (item: string) => item)
.onMove((from: number, to: number) => {
let tmp = this.numbers.splice(from, 1);
this.numbers.splice(to, 0, tmp[0])
})
}
.lanes({ minLength: 80, maxLength: 400 })
.width('100%')
.height('100%')
.backgroundColor('#ff9fb0cd')
}
.width('100%')
.height('100%')
.backgroundColor('#0D182431')
.padding({ top: 5 })
}
build() {
Column() {
Text('Drag Up')
.draggable(true)
.fontSize(20)
.fontColor(Color.Black)
.margin(10)
.bindSheet($$this.isShow, this.myBuilder(), {
height: this.sheetHeight,
backgroundColor: Color.Blue,
blurStyle: BlurStyle.Thick,
showClose: true,
title: { title: 'Title', subtitle: 'Subtitle' },
})
.gesture(
GestureGroup(GestureMode.Sequence,
PanGesture({ fingers: 1, direction: null, distance: 0 })
.onActionUpdate((event: GestureEvent) => {
this.isShow = true
console.info('Output:', event.offsetY)
this.sheetHeight = Math.abs(event.offsetY)
})
)
)
}
.justifyContent(FlexAlign.End)
.width('100%')
.height('100%')
.backgroundColor(Color.White)
}
}
Test Results
- The drag gesture successfully triggers the half-modal sheet to appear.
- The sheet’s height dynamically responds to the drag distance.
- The app compiles and runs correctly without code errors.
Limitations or Considerations
- This example supports API Version 19 Release and above.
- Requires HarmonyOS 5.1.1 Release SDK or later.
- Must be built and run using DevEco Studio 5.1.1 Release or later.

Top comments (0)