1# Binding a Semi-Modal Page (bindSheet)
2
3A semi-modal page, implemented using [bindSheet](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#bindsheet), is a modal, non-full-screen popup interaction page by default, allowing parts of the underlying parent view to be visible. This helps users retain the context of their parent view while interacting with the semi-modal.
4
5Semi-modal pages are suitable for displaying simple tasks or information panels, such as personal information, text introductions, sharing panels, creating schedules, and adding content. If a semi-modal page needs to be displayed in a way that could potentially affect the parent view, it can be configured to use a non-modal interaction form.
6
7Semi-modal pages have different form capabilities on devices of different widths. For details about the form requirements on devices with different widths, see the [preferType](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#bindoptions) property. You can use **bindSheet** to build semi-modal transition effects. For details, see [Modal Transition](arkts-modal-transition.md#creating-sheet-transition-with-bindsheet). For complex or lengthy user processes, consider other transition methods instead of semi-modals, such as [full-modal transition](arkts-contentcover-page.md) and [navigation transition](arkts-navigation-transition.md).
8
9## Constraints
10
11 - When a [UIExtension](../reference/apis-arkui/js-apis-arkui-uiExtension.md) is embedded in a semi-modal, launching another semi-modal or popup window within the UIExtension is not allowed.
12
13 - In scenarios without secondary confirmation or custom close behavior, avoid using the [shouldDismiss/onWilDismiss](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#sheetoptions) API.
14
15## Lifecycle
16
17The semi-modal page provides lifecycle callbacks to notify the application of the lifecycle status of the popup. These callbacks are triggered in the following order: onWillAppear -> onAppear -> onWillDisappear -> onDisappear.
18
19| Name           |Type| Description                      |
20| ----------------- | ------ | ---------------------------- |
21| onWillAppear    | () => void | Callback for when the semi-modal page is about to be displayed (before the animation starts).|
22| onAppear    | () => void  | Callback for when the semi-modal page is displayed (after the animation ends). |
23| onWillDisappear | () => void | Callback for when the semi-modal page is about to disappear (before the animation starts).|
24| onDisappear |() => void  | Callback for when the semi-modal page disappears (after the animation ends).    |
25
26## Using Nested Scrolling
27
28The priority of operations during scrolling in the content area of a semi-modal panel is as follows:
29
301. 1. Content at the top and content that cannot be scrolled
31
32   Swiping up: The sheet will attempt to expand upwards. If no expansion is possible, the content will scroll.
33
34   Swiping down: The panel will attempt to contract downwards. If no contraction is possible, the panel will close.
352. 2. Content in the middle (scrollable both up and down)
36
37   Swiping up or down: The content will scroll until it reaches the top or bottom of the panel.
38
393. 3. Content at the bottom (scrollable)
40
41   Swiping up: The content area will display a rebound effect without changing the panel position.
42
43   Swiping down: The content will scroll until it reaches the top.
44
45The default nested mode for the above semi-modal interactions is: {Forward:PARENT\_FIRST,Backward:SELF\_FIRST}.
46
47If you want to define a scrollable container, such as **List** or **Scroll**, in the panel content builder, and combine it with the semi-modal's interaction capabilities, you must set the nested scrolling attributes for the scrollable container in the vertical direction.
48
49```ts
50.nestedScroll({
51    // Nested scrolling options for the scrollable component when it scrolls towards the end, with the gesture upwards.
52    scrollForward: NestedScrollMode.PARENT_FIRST,
53    // Nested scrolling options for the scrollable component when it scrolls towards the start, with the gesture downwards.
54    scrollBackward: NestedScrollMode.SELF_FIRST,
55})
56```
57
58The sample code is as follows:
59
60```ts
61@Entry
62@Component
63struct SheetDemo {
64  @State isShowSheet: boolean = false
65  private items : number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
66
67  @Builder
68  SheetBuilder() {
69    Column() {
70      // Step 1: Customize a scrollable container.
71      List({space:'10vp'}) {
72        ForEach(this.items,(item : number) => {
73          ListItem() {
74            Text(String(item)).fontSize(16).fontWeight(FontWeight.Bold)
75          }.width('90%').height('80vp').backgroundColor('#ff53ecd9').borderRadius(10)
76        })
77      }.alignListItem(ListItemAlign.Center).margin({top:'10vp'}).width('100%').height('900px')
78      // Step 2: Set the nested scrolling attributes of the scrollable component.
79      .nestedScroll({
80        scrollForward: NestedScrollMode.PARENT_FIRST,
81        scrollBackward: NestedScrollMode.SELF_FIRST,
82      })
83
84      Text("Non-scrollable area").width('100%').backgroundColor(Color.Gray)
85        .layoutWeight(1)
86        .textAlign(TextAlign.Center)
87        .align(Alignment.Top)
88    }.width('100%').height('100%')
89  }
90  build() {
91    Column() {
92      Button('Open Sheet').width('90%').height('80vp')
93        .onClick(()=>{
94          this.isShowSheet = !this.isShowSheet
95        })
96        .bindSheet($$this.isShowSheet, this.SheetBuilder(), {
97          detents:[SheetSize.MEDIUM, SheetSize.LARGE, 600],
98          preferType: SheetType.BOTTOM,
99          title: {title: 'Nested Scrolling Scenario'},
100        })
101    }.width('100%').height('100%')
102    .justifyContent(FlexAlign.Center)
103  }
104}
105```
106
107## Secondary Confirmation Capability
108
109To implement the secondary confirmation capability, you are advised to use the **onWillDismiss** API, with which you can handle secondary confirmation or custom close behavior in the callback.
110
111> **NOTE**
112>
113> After the **onWillDismiss** API is declared, all close operations of the semi-modal page, including side swiping, touching the close button, touching the mask, and pulling down, must be implemented by calling the **dismiss** API. If this logic is not implemented, the semi-modal page will not respond to the above close operations.
114
115```ts
116// Step 1: Declare the onWillDismiss callback.
117onWillDismiss: ((DismissSheetAction: DismissSheetAction) => {
118// Step 2: Implement the secondary confirmation interaction, using an AlertDialog component to prompt the user for confirmation.
119  AlertDialog.show(
120    {
121      message: 'Do you want to close the semi-modal?',
122      autoCancel: true,
123      alignment: DialogAlignment.Bottom,
124      gridCount: 4,
125      offset: { dx: 0, dy: -20 },
126      primaryButton: {
127        value: 'cancel',
128        action: () => {
129          console.info('Callback when the cancel button is clicked')
130        }
131      },
132      secondaryButton: {
133        enabled: true,
134        defaultFocus: true,
135        style: DialogButtonStyle.HIGHLIGHT,
136        value: 'ok',
137        // Step 3: Define the logic for closing the semi-modal within the AlertDialog button callback.
138        action: () => {
139          // Step 4: Call dismiss() to close the semi-modal when the logic in step 3 is triggered.
140          DismissSheetAction.dismiss()
141          console.info('Callback when the ok button is clicked')
142        }
143      },
144      cancel: () => {
145        console.info('AlertDialog Closed callbacks')
146      }
147    }
148  )
149})
150```
151
152## Blocking Specific Dismiss Behavior
153
154After the **onWillDismiss** API is declared, it takes control over all dismiss behaviors of the semi-modal. This means that the semi-modal can be dismissed only when you explicitly call the **dismiss** API. This allows you to implement custom logic to control when the semi-modal should close.
155For example, you might want the semi-modal to close only when the user swipes down. Here's how you can implement this:
156
157```ts
158onWillDismiss: ((DismissSheetAction: DismissSheetAction) => {
159  if (DismissSheetAction.reason == DismissReason.SLIDE_DOWN) {
160    DismissSheetAction.dismiss() // Register the dismiss behavior.
161  }
162}),
163```
164
165To enhance the user experience during the swiping down action, you can use the **onWillSpringBackWhenDismiss** API.
166This API allows you to control the rebound effect when the semi-modal is swiped down. By default, the semi-modal will rebound when swiped down, but you can prevent this behavior by not calling **SpringBackAction.springBack()**.
167
168Here is the specific code to prevent the rebound effect when the semi-modal is swiped down:
169
170```ts
171onWillDismiss: ((DismissSheetAction: DismissSheetAction) => {
172  if (DismissSheetAction.reason == DismissReason.SLIDE_DOWN) {
173    DismissSheetAction.dismiss() // Register the dismiss behavior.
174  }
175}),
176
177onWillSpringBackWhenDismiss: ((SpringBackAction: SpringBackAction) => {
178 // Do not call SpringBackAction.springBack(), so no rebound behavior occurs.
179}),
180```
181