• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Custom Dialog Box (CustomDialog)
2
3A custom dialog box is a dialog box you customize by using APIs of the **CustomDialogController** class. You can set the style and content to your preference for a custom dialog box.
4
5> **NOTE**
6>
7> The APIs of this module are supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version.
8
9
10## APIs
11
12constructor(value: CustomDialogControllerOptions)
13
14Defines a custom dialog box.
15
16> **NOTE**
17>
18> No parameters of the custom dialog box can be dynamically updated.
19
20**Atomic service API**: This API can be used in atomic services since API version 11.
21
22**System capability**: SystemCapability.ArkUI.ArkUI.Full
23
24**Parameters**
25
26| Name| Type                                                        | Mandatory| Description                  |
27| ------ | ------------------------------------------------------------ | ---- | ---------------------- |
28| value  | [CustomDialogControllerOptions](#customdialogcontrolleroptions) | Yes  | Parameters of the custom dialog box.|
29
30## CustomDialogControllerOptions
31
32**System capability**: SystemCapability.ArkUI.ArkUI.Full
33
34| Name                          | Type                                    | Mandatory  | Description                                    |
35| ----------------------------- | ---------------------------------------- | ---- | ---------------------------------------- |
36| builder                       | [CustomDialog](../../../ui/arkts-common-components-custom-dialog.md) | Yes   | Builder of the custom dialog box content.<br>**NOTE**<br>If the builder uses a callback as the input parameter, as in **build: custombuilder({ callback: ()=> {...}})**, pay attention to the binding of **this**.<br>To listen for data changes in the builder, use the @Link decorator; other decorators, such as @Prop and @ObjectLink, do not apply.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
37| cancel                        | () =&gt; void                  | No   | Callback invoked when the dialog box is closed after the Back button or mask is touched or the Esc key is pressed.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
38| autoCancel                    | boolean                                  | No   | Whether to close the dialog box when the mask is touched. The value **true** means to close the dialog box when the mask is touched, and **false** means the opposite.<br>Default value: **true**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
39| alignment                     | [DialogAlignment](ts-methods-alert-dialog-box.md#dialogalignment) | No   | Alignment mode of the dialog box in the vertical direction.<br>Default value: **DialogAlignment.Default**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
40| offset                        | [Offset](ts-types.md#offset)             | No   | Offset of the dialog box relative to the alignment position.<br>Default value: **{dx: 0, dy: 0}**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
41| customStyle                   | boolean                                  | No   | Whether to use a custom style for the dialog box.<br>When this parameter is set to **false** (default value):<br>1. The rounded corner radius is 32 vp.<br>2. If the width and height of the dialog box are not set, the dialog box automatically adapts its width to the grid system and its height to the child components.<br>3. The set width of the dialog box cannot exceed the maximum width in the default style (100% width for a custom node), and the set height cannot exceed the maximum height (100% height for a custom node).<br>When this parameter is set to **true**:<br>1. The corner radius is 0, and the background color is transparent.<br>2. The width, height, border width, border style, border color, and shadow width cannot be set for the dialog box.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
42| gridCount<sup>8+</sup>        | number                                   | No   | Number of [grid columns](../../../ui/arkts-layout-development-grid-layout.md) occupied by the dialog box.<br>The default value is subject to the window size, and the maximum value is the maximum number of columns supported by the system. If this parameter is set to an invalid value, the default value is used.<br>Value range: an integer no less than 0<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
43| maskColor<sup>10+</sup>       | [ResourceColor](ts-types.md#resourcecolor) | No   | Custom mask color.<br>Default value: **0x33000000**<br>**Atomic service API**: This API can be used in atomic services since API version 11.             |
44| maskRect<sup>10+</sup>        | [Rectangle](ts-methods-alert-dialog-box.md#rectangle8) | No    | Mask area of the dialog box. Events outside the mask area are transparently transmitted, and events within the mask area are not.<br>Default value: **{ x: 0, y: 0, width: '100%', height: '100%' }**<br>**NOTE**<br>**maskRect** does not take effect when **showInSubWindow** is set to **true**.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
45| openAnimation<sup>10+</sup>   | [AnimateParam](ts-explicit-animation.md#animateparam) | No   | Parameters for defining the open animation of the dialog box.<br>**NOTE**<br>**tempo**: The default value is **1**; a value less than or equal to 0 is handled as the default value.<br>**iterations**: The default value is **1**, indicating that the animation is played once; any other value is handled as the default value.<br>**playMode**: The default value is **PlayMode.Normal**; any other value is handled as the default value.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
46| closeAnimation<sup>10+</sup>  | [AnimateParam](ts-explicit-animation.md#animateparam) | No   | Parameters for defining the close animation of the dialog box.<br>**NOTE**<br>**tempo**: The default value is **1**; a value less than or equal to 0 is handled as the default value.<br>**iterations**: The default value is **1**, indicating that the animation is played once; any other value is handled as the default value.<br>**playMode**: The default value is **PlayMode.Normal**; any other value is handled as the default value.<br>For page transition, you are advised to use the default close animation.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
47| showInSubWindow<sup>10+</sup> | boolean                                  | No   | Whether to show the dialog box in a subwindow when the dialog box needs to be displayed outside the main window.<br>Default value: **false**<br>**NOTE**<br>A dialog box whose **showInSubWindow** attribute is **true** cannot trigger the display of another dialog box whose **showInSubWindow** attribute is also **true**. Avoid using the **CalendarPicker**, **CalendarPickerDialog**, **DatePickerDialog**, **TextPickerDialog**, and **TimePickerDialog** components in the dialog box where **showInSubWindow** is set to **true**, as the dialog box may affect the behavior of these components.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
48| backgroundColor<sup>10+</sup> | [ResourceColor](ts-types.md#resourcecolor)      | No  | Background color of the dialog box.<br>Default value: **Color.Transparent**<br>**NOTE**<br>If the content builder also has the background color set, the background color set here will be overridden by the background color of the content builder.<br>When **backgroundColor** is set to a non-transparent color, **backgroundBlurStyle** must be set to **BlurStyle.NONE**; otherwise, the color display may not meet the expected effect.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
49| cornerRadius<sup>10+</sup>    | [Dimension](ts-types.md#dimension10) \| [BorderRadiuses](ts-types.md#borderradiuses9) | No  | Radius of the rounded corners of the background.<br>You can set separate radiuses for the four rounded corners.<br>Default value: **{ topLeft: '32vp', topRight: '32vp', bottomLeft: '32vp', bottomRight: '32vp' }**<br>**NOTE**<br>This attribute must be used together with the [borderRadius](ts-universal-attributes-border.md#borderradius) attribute.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
50| isModal<sup>11+</sup> | boolean | No| Whether the dialog box is a modal. A modal dialog box has a mask applied, while a non-modal dialog box does not.<br>Default value: **true**<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
51| onWillDismiss<sup>12+</sup> | Callback<[DismissDialogAction](#dismissdialogaction12)> | No| Callback for interactive closure of the dialog box.<br>**NOTE**<br>1. If this callback is registered, the dialog box will not be closed immediately after the user touches the mask or the Back button, presses the Esc key, or swipes left or right on the screen. The **reason** parameter in the callback is used to determine whether the dialog box can be closed. The reason returned by the component does not support the value **CLOSE_BUTTON**.<br>2. In the **onWillDismiss** callback, another **onWillDismiss** callback is not allowed.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
52| borderWidth<sup>12+</sup> | [Dimension](ts-types.md#dimension10) \| [EdgeWidths](ts-types.md#edgewidths9)  | No| Border width of the dialog box.<br>You can set the width for all four sides or set separate widths for individual sides.<br>Default value: **0**<br> When set to a percentage, the value defines the border width as a percentage of the parent dialog box's width.<br>If the left and right borders are greater than its width, or the top and bottom borders are greater than its height, the dialog box may not display as expected.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
53| borderColor<sup>12+</sup> | [ResourceColor](ts-types.md#resourcecolor) \| [EdgeColors](ts-types.md#edgecolors9)  | No| Border color of the dialog box.<br>Default value: **Color.Black**<br>**borderColor** must be used with **borderWidth** in pairs.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
54| borderStyle<sup>12+</sup> | [BorderStyle](ts-appendix-enums.md#borderstyle) \| [EdgeStyles](ts-types.md#edgestyles9)  | No| Border style of the dialog box.<br>Default value: **BorderStyle.Solid**<br>**borderStyle** must be used with **borderWidth** in pairs.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
55| width<sup>12+</sup> | [Dimension](ts-types.md#dimension10) | No  | Width of the dialog box.<br>**NOTE**<br>- Default maximum width of the dialog box: 400 vp<br>- When this parameter is set to a percentage, the reference width of the dialog box is the width of the window where the dialog box is located. You can decrease or increase the width as needed.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
56| height<sup>12+</sup> | [Dimension](ts-types.md#dimension10)   | No| Height of the dialog box.<br>**NOTE**<br>- Default maximum height of the dialog box: 0.9 x (Window height – Safe area)<br>- When this parameter is set to a percentage, the reference height of the dialog box is the height of the window where the dialog box is located minus the safe area. You can decrease or increase the height as needed.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
57| shadow<sup>12+</sup> | [ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions) \| [ShadowStyle](ts-universal-attributes-image-effect.md#shadowstyle10)   | No| Shadow of the dialog box.<br> Default value on 2-in-1 devices: **ShadowStyle.OUTER_FLOATING_MD** when the dialog box is focused and **ShadowStyle.OUTER_FLOATING_SM** otherwise<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
58| backgroundBlurStyle<sup>12+</sup> | [BlurStyle](ts-universal-attributes-background.md#blurstyle9)                 | No  | Background blur style of the dialog box.<br>Default value: **BlurStyle.COMPONENT_ULTRA_THICK**<br>**NOTE**<br>Setting this parameter to **BlurStyle.NONE** disables the background blur. When **backgroundBlurStyle** is set to a value other than **NONE**, do not set **backgroundColor**. If you do, the color display may not produce the expected visual effect.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
59| backgroundBlurStyleOptions<sup>18+</sup> | [BackgroundBlurStyleOptions](ts-universal-attributes-background.md#backgroundblurstyleoptions10)| No| Options for customizing the background blur style.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
60| backgroundEffect<sup>18+</sup> | [BackgroundEffectOptions](ts-universal-attributes-background.md#backgroundeffectoptions11) | No| Options for customizing the background effect.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
61| keyboardAvoidMode<sup>12+</sup> | [KeyboardAvoidMode](ts-types.md#keyboardavoidmode12) | No| How the dialog box avoids the soft keyboard when it is brought up.<br>Default value: **KeyboardAvoidMode.DEFAULT**<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
62| enableHoverMode<sup>14+</sup>     | boolean | No  | Whether to enable the hover state.<br>Default value: **false**, meaning not to enable the hover state.<br>**Atomic service API**: This API can be used in atomic services since API version 14.|
63| hoverModeArea<sup>14+</sup>       | [HoverModeAreaType](ts-appendix-enums.md#hovermodeareatype14) | No  | Display area of the dialog box in the hover state.<br>Default value: **HoverModeAreaType.BOTTOM_SCREEN**<br>**Atomic service API**: This API can be used in atomic services since API version 14.|
64| onWillAppear<sup>18+</sup> | Callback&lt;void&gt; | No| Event callback when the dialog box is about to appear.<br>**NOTE**<br>1. The normal timing sequence is as follows: onWillAppear > onDidAppear > onWillDisappear > onDidDisappear.<br>2. You can set the callback event for changing the dialog box display effect in **onWillAppear**. The settings take effect next time the dialog box appears.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
65| onDidAppear<sup>18+</sup> | Callback&lt;void&gt; | No| Event callback when the dialog box appears.<br>**NOTE**<br>1. The normal timing sequence is as follows: onWillAppear > onDidAppear > onWillDisappear > onDidDisappear.<br>2. You can set the callback event for changing the dialog box display effect in **onDidAppear**. The settings take effect next time the dialog box appears.<br>3. If the dialog is dismissed before its entrance animation is finished, the animation will be interrupted, and **onDidAppear** will not be triggered.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
66| onWillDisappear<sup>18+</sup> | Callback&lt;void&gt; | No| Event callback when the dialog box is about to disappear.<br>**NOTE**<br>1. The normal timing sequence is as follows: onWillAppear > onDidAppear > onWillDisappear > onDidDisappear.<br> **Atomic service API**: This API can be used in atomic services since API version 18.|
67| onDidDisappear<sup>18+</sup> | Callback&lt;void&gt; | No| Event callback when the dialog box disappears.<br>**NOTE**<br>1. The normal timing sequence is as follows: onWillAppear > onDidAppear > onWillDisappear > onDidDisappear.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
68| keyboardAvoidDistance<sup>15+</sup>       | [LengthMetrics](../js-apis-arkui-graphics.md#lengthmetrics12) | No  | Distance between the dialog box and the keyboard after keyboard avoidance is applied.<br>**NOTE**<br>- Default value: **16vp**<br>- Default unit: vp<br>- This parameter takes effect only when **keyboardAvoidMode** is set to **DEFAULT**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
69| levelMode<sup>15+</sup>       | [LevelMode](../js-apis-promptAction.md#levelmode15) | No  | Display level of the dialog box.<br>**NOTE**<br>- Default value: **LevelMode.OVERLAY.**<br>- This parameter takes effect only when **showInSubWindow** is set to **false**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
70| levelUniqueId<sup>15+</sup>       | number | No  | [Unique ID](../js-apis-arkui-frameNode.md#getuniqueid12) of the node under the display level for the page-level dialog box.<br>**NOTE**<br>- This parameter takes effect only when **levelMode** is set to **LevelMode.EMBEDDED**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
71| immersiveMode<sup>15+</sup>       | [ImmersiveMode](../js-apis-promptAction.md#immersivemode15) | No  | Mask effect for the page-level dialog box.<br>**NOTE**<br>- Default value: **ImmersiveMode.DEFAULT**<br>- This parameter takes effect only when **levelMode** is set to **LevelMode.EMBEDDED**.<br>**Atomic service API**: This API can be used in atomic services since API version 15.|
72| levelOrder<sup>18+</sup>       | [LevelOrder](../js-apis-promptAction.md#levelorder18) | No  | Display order of the dialog box.<br>**NOTE**<br>- Default value: **LevelOrder.clamp(0)**<br>- Dynamic updating is not supported.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
73| focusable<sup>18+</sup>       | boolean | No  | Whether the dialog box can gain focus.<br>Default value: **true**<br>**NOTE**<br>Only dialog boxes that are displayed on top of the current window can gain focus.<br>**Atomic service API**: This API can be used in atomic services since API version 18.|
74
75> **NOTE**
76>
77> - Pressing the Back or ESC key closes the dialog box.
78> - If the dialog box reaches its maximum allowable height on the screen when avoiding the soft keyboard, it reduces its height to fit.
79>   It should be noted that this height adjustment is applied to the outermost container. If a child component within this container has been assigned a larger fixed height, since the container does not clip its content by default, parts of the dialog box may still be displayed off-screen.
80> - Use the custom dialog box to contain simple alert messages only. Do not use it as a page. When the dialog box avoids the soft keyboard, there is a 16 vp safe spacing between the two.
81>
82> - Currently, dialog boxes in ArkUI do not close automatically when you switch pages unless you manually call **close**. To enable a dialog box to be covered during page navigation, consider using the **Navigation** component. For details, see the [page display mode: dialog mode](../../../ui/arkts-navigation-navigation.md#page-display-mode).
83
84## DismissDialogAction<sup>12+</sup>
85
86Provides information about the action to dismiss the dialog box.
87
88**Atomic service API**: This API can be used in atomic services since API version 12.
89
90**System capability**: SystemCapability.ArkUI.ArkUI.Full
91
92### Properties
93
94| Name   | Type                                                        | Readable| Writable| Description                                                        |
95| ------- | ------------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ |
96| dismiss | Callback&lt;void&gt;                                         | No  | No  | Callback for dismissing the dialog box. This API is called only when the dialog box needs to be exited.|
97| reason  | [DismissReason](../js-apis-promptAction.md#dismissreason12) | No  | No  | Reason why the dialog box cannot be dismissed. You must specify whether to close the dialog box for each of the listed actions.|
98
99## CustomDialogController
100
101**Atomic service API**: This API can be used in atomic services since API version 11.
102
103### Objects to Import
104
105```ts
106dialogController : CustomDialogController | null = new CustomDialogController(CustomDialogControllerOptions)
107```
108> **NOTE**
109>
110> **CustomDialogController** is effective only when it is a member variable of the **@CustomDialog** and **@Component** decorated struct and is defined in the **@Component** decorated struct. For details, see the following example.
111
112### constructor
113
114constructor(value: CustomDialogControllerOptions)
115
116Constructor for a custom dialog box.
117
118**Atomic service API**: This API can be used in atomic services since API version 11.
119
120**System capability**: SystemCapability.ArkUI.ArkUI.Full
121
122**Parameters**
123
124| Name| Type                                                        | Mandatory| Description                  |
125| ------ | ------------------------------------------------------------ | ---- | ---------------------- |
126| value  | [CustomDialogControllerOptions](#customdialogcontrolleroptions) | Yes  | Parameters of the custom dialog box.|
127
128### open
129
130open()
131
132Opens the content of the custom dialog box. This API can be called multiple times. If the dialog box is displayed in a subwindow, no new subwindow is allowed.
133
134**Atomic service API**: This API can be used in atomic services since API version 11.
135
136**System capability**: SystemCapability.ArkUI.ArkUI.Full
137
138
139### close
140
141close()
142
143**Atomic service API**: This API can be used in atomic services since API version 11.
144
145**System capability**: SystemCapability.ArkUI.ArkUI.Full
146
147
148Closes the custom dialog box. If the dialog box is closed, this API does not take effect.
149
150## Example
151
152### Example 1: Opening Nested Dialog Boxes
153
154This example demonstrates how to open one or more custom dialog boxes within another custom dialog box.
155
156```ts
157// xxx.ets
158@CustomDialog
159struct CustomDialogExampleTwo {
160  controllerTwo?: CustomDialogController
161  build() {
162    Column() {
163      Text('I am the second dialog box')
164        .fontSize(30)
165        .height(100)
166      Button('Close Second Dialog Box')
167        .onClick(() => {
168          if (this.controllerTwo != undefined) {
169            this.controllerTwo.close()
170          }
171        })
172        .margin(20)
173    }
174  }
175}
176@CustomDialog
177@Component
178struct CustomDialogExample {
179  @Link textValue: string
180  @Link inputValue: string
181  dialogControllerTwo: CustomDialogController | null = new CustomDialogController({
182    builder: CustomDialogExampleTwo(),
183    alignment: DialogAlignment.Bottom,
184    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
185      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
186      console.log("dialog onWillDismiss")
187      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
188        dismissDialogAction.dismiss()
189      }
190      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
191        dismissDialogAction.dismiss()
192      }
193    },
194    offset: { dx: 0, dy: -25 } })
195  controller?: CustomDialogController
196  // You can pass in multiple other controllers in the CustomDialog to open one or more other CustomDialogs in the CustomDialog. In this case, you must place the controller pointing to the self behind all controllers.
197  cancel: () => void = () => {
198  }
199  confirm: () => void = () => {
200  }
201
202  build() {
203    Column() {
204      Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
205      TextInput({ placeholder: '', text: this.textValue }).height(60).width('90%')
206        .onChange((value: string) => {
207          this.textValue = value
208        })
209      Text('Are you sure you want to change the text?').fontSize(16).margin({ bottom: 10 })
210      Flex({ justifyContent: FlexAlign.SpaceAround }) {
211        Button('No')
212          .onClick(() => {
213            if (this.controller != undefined) {
214              this.controller.close()
215              this.cancel()
216            }
217          }).backgroundColor(0xffffff).fontColor(Color.Black)
218        Button('OK')
219          .onClick(() => {
220            if (this.controller != undefined) {
221              this.inputValue = this.textValue
222              this.controller.close()
223              this.confirm()
224            }
225          }).backgroundColor(0xffffff).fontColor(Color.Red)
226      }.margin({ bottom: 10 })
227
228      Button('Open Second Dialog Box')
229        .onClick(() => {
230          if (this.dialogControllerTwo != null) {
231            this.dialogControllerTwo.open()
232          }
233        })
234        .margin(20)
235    }.borderRadius(10)
236    // When using the border or cornerRadius attribute, use it together with the borderRadius attribute.
237  }
238}
239@Entry
240@Component
241struct CustomDialogUser {
242  @State textValue: string = ''
243  @State inputValue: string = 'click me'
244  dialogController: CustomDialogController | null = new CustomDialogController({
245    builder: CustomDialogExample({
246      cancel: ()=> { this.onCancel() },
247      confirm: ()=> { this.onAccept() },
248      textValue: $textValue,
249      inputValue: $inputValue
250    }),
251    cancel: this.exitApp,
252    autoCancel: true,
253    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
254      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
255      console.log("dialog onWillDismiss")
256      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
257        dismissDialogAction.dismiss()
258      }
259      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
260        dismissDialogAction.dismiss()
261      }
262    },
263    alignment: DialogAlignment.Bottom,
264    offset: { dx: 0, dy: -20 },
265    gridCount: 4,
266    customStyle: false,
267    cornerRadius: 10,
268  })
269
270  // Set dialogController to null when the custom component is about to be destroyed.
271  aboutToDisappear() {
272    this.dialogController = null // Set dialogController to null.
273  }
274
275  onCancel() {
276    console.info('Callback when the first button is clicked')
277  }
278
279  onAccept() {
280    console.info('Callback when the second button is clicked')
281  }
282
283  exitApp() {
284    console.info('Click the callback in the blank area')
285  }
286  build() {
287    Column() {
288      Button(this.inputValue)
289        .onClick(() => {
290          if (this.dialogController != null) {
291            this.dialogController.open()
292          }
293        }).backgroundColor(0x317aff)
294    }.width('100%').margin({ top: 5 })
295  }
296}
297```
298
299
300
301### Example 2: Opening a Dialog Box Outside the Main Window
302
303This example demonstrates how to configure a dialog box to display outside the main window on a 2-in-1 device by setting **showInSubWindow** to **true**.
304
305```ts
306// xxx.ets
307@CustomDialog
308struct CustomDialogExample {
309  controller?: CustomDialogController
310  cancel: () => void = () => {
311  }
312  confirm: () => void = () => {
313  }
314  build() {
315    Column() {
316      Text('Dialog box outside the main window')
317        .fontSize(30)
318        .height(100)
319      Button('Close')
320        .onClick(() => {
321          if (this.controller != undefined) {
322            this.controller.close()
323          }
324        })
325        .margin(20)
326    }
327  }
328}
329@Entry
330@Component
331struct CustomDialogUser {
332  dialogController: CustomDialogController | null = new CustomDialogController({
333    builder: CustomDialogExample({
334      cancel: ()=> { this.onCancel() },
335      confirm: ()=> { this.onAccept() }
336    }),
337    cancel: this.existApp,
338    autoCancel: true,
339    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
340      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
341      console.log("dialog onWillDismiss")
342      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
343        dismissDialogAction.dismiss()
344      }
345      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
346        dismissDialogAction.dismiss()
347      }
348    },
349    alignment: DialogAlignment.Center,
350    offset: { dx: 0, dy: -20 },
351    gridCount: 4,
352    showInSubWindow: true,
353    isModal: true,
354    customStyle: false,
355    cornerRadius: 10,
356    focusable: true
357  })
358  // Set dialogController to null when the custom component is about to be destroyed.
359  aboutToDisappear() {
360    this.dialogController = null // Set dialogController to null.
361  }
362
363  onCancel() {
364    console.info('Callback when the first button is clicked')
365  }
366
367  onAccept() {
368    console.info('Callback when the second button is clicked')
369  }
370
371  existApp() {
372    console.info('Click the callback in the blank area')
373  }
374
375  build() {
376    Column() {
377      Button('Click Me')
378        .onClick(() => {
379          if (this.dialogController != null) {
380            this.dialogController.open()
381          }
382        }).backgroundColor(0x317aff)
383    }.width('100%').margin({ top: 5 })
384  }
385}
386```
387
388![en-us_image_custom-showinsubwindow](figures/en-us_image_custom-showinsubwindow.jpg)
389
390### Example 3: Setting the Dialog Box Style
391This example demonstrates how to set styles of a custom dialog box, including the width, height, background color, and shadow.
392```ts
393// xxx.ets
394@CustomDialog
395struct CustomDialogExample {
396  controller?: CustomDialogController
397  cancel: () => void = () => {
398  }
399  confirm: () => void = () => {
400  }
401  build() {
402    Column() {
403      Text('This is a custom dialog box')
404        .fontSize(30)
405        .height(100)
406      Button('Close')
407        .onClick(() => {
408          if (this.controller != undefined) {
409            this.controller.close()
410          }
411        })
412        .margin(20)
413    }
414  }
415}
416@Entry
417@Component
418struct CustomDialogUser {
419  dialogController: CustomDialogController | null = new CustomDialogController({
420    builder: CustomDialogExample({
421      cancel: ()=> { this.onCancel() },
422      confirm: ()=> { this.onAccept() }
423    }),
424    cancel: this.existApp,
425    autoCancel: true,
426    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
427      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
428      console.log("dialog onWillDismiss")
429      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
430        dismissDialogAction.dismiss()
431      }
432      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
433        dismissDialogAction.dismiss()
434      }
435    },
436    alignment: DialogAlignment.Center,
437    offset: { dx: 0, dy: -20 },
438    customStyle: false,
439    cornerRadius: 20,
440    width: 300,
441    height: 200,
442    borderWidth: 1,
443    borderStyle: BorderStyle.Dashed,// borderStyle must be used with borderWidth in pairs.
444    borderColor: Color.Blue,// borderColor must be used with borderWidth in pairs.
445    backgroundColor: Color.White,
446    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
447  })
448  // Set dialogController to null when the custom component is about to be destroyed.
449  aboutToDisappear() {
450    this.dialogController = null // Set dialogController to null.
451  }
452
453  onCancel() {
454    console.info('Callback when the first button is clicked')
455  }
456
457  onAccept() {
458    console.info('Callback when the second button is clicked')
459  }
460
461  existApp() {
462    console.info('Click the callback in the blank area')
463  }
464
465  build() {
466    Column() {
467      Button('Click Me')
468        .onClick(() => {
469          if (this.dialogController != null) {
470            this.dialogController.open()
471          }
472        }).backgroundColor(0x317aff)
473    }.width('100%').margin({ top: 5 })
474  }
475}
476```
477
478![en-us_image_custom_style](figures/en-us_image_custom_style.gif)
479
480### Example 4: Configuring a Dialog Box in the Hover State
481
482This example demonstrates how to set the layout area of a dialog box in the hover state on a foldable device.
483
484```ts
485@CustomDialog
486@Component
487struct CustomDialogExample {
488  @Link textValue: string;
489  @Link inputValue: string;
490  controller?: CustomDialogController;
491
492  build() {
493    Column() {
494      Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
495      TextInput({ placeholder: '', text: this.textValue }).height(60).width('90%')
496        .onChange((value: string) => {
497          this.textValue = value;
498        })
499      Text('Are you sure you want to change the text?').fontSize(16).margin({ bottom: 10 })
500      Flex({ justifyContent: FlexAlign.SpaceAround }) {
501        Button('No')
502          .onClick(() => {
503            if (this.controller != undefined) {
504              this.controller.close();
505            }
506          }).backgroundColor(0xffffff).fontColor(Color.Black)
507        Button('OK')
508          .onClick(() => {
509            if (this.controller != undefined) {
510              this.inputValue = this.textValue;
511              this.controller.close();
512            }
513          }).backgroundColor(0xffffff).fontColor(Color.Red)
514      }.margin({ bottom: 10 })
515
516      Button('Open Second Dialog Box')
517        .margin(20)
518    }.borderRadius(10)
519    // When using the border or cornerRadius attribute, use it together with the borderRadius attribute.
520  }
521}
522@Entry
523@Component
524struct CustomDialogUser {
525  @State textValue: string = '';
526  @State inputValue: string = 'click me';
527  dialogController: CustomDialogController | null = new CustomDialogController({
528    builder: CustomDialogExample({
529      textValue: $textValue,
530      inputValue: $inputValue
531    }),
532    cancel: this.exitApp,
533    autoCancel: true,
534    onWillDismiss: (dismissDialogAction: DismissDialogAction)=> {
535      console.info("reason=" + JSON.stringify(dismissDialogAction.reason));
536      console.log("dialog onWillDismiss");
537      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
538        dismissDialogAction.dismiss();
539      }
540      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
541        dismissDialogAction.dismiss();
542      }
543    },
544    alignment: DialogAlignment.Bottom,
545    offset: { dx: 0, dy: -20 },
546    gridCount: 4,
547    customStyle: false,
548    cornerRadius: 10,
549    enableHoverMode: true,
550    hoverModeArea: HoverModeAreaType.TOP_SCREEN
551  })
552
553  // Set dialogController to null when the custom component is about to be destroyed.
554  aboutToDisappear() {
555    this.dialogController = null; // Set dialogController to null.
556  }
557
558  exitApp() {
559    console.info('Click the callback in the blank area');
560  }
561
562  build() {
563    Column() {
564      Button(this.inputValue)
565        .onClick(() => {
566          if (this.dialogController != null) {
567            this.dialogController.open();
568          }
569        }).backgroundColor(0x317aff)
570    }.width('100%').margin({ top: 5 })
571  }
572}
573```
574
575![en-us_image_custom](figures/en-us_image_custom_hovermode.gif)
576