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>**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 sub-window 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| keyboardAvoidMode<sup>12+</sup> | [KeyboardAvoidMode](../js-apis-promptAction.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.|
60| enableHoverMode<sup>13+</sup>              | boolean | No  | Whether to enable the hover state.<br>Default value: **false**, meaning not to enable the hover state.|
61| hoverModeArea<sup>13+</sup>              | [HoverModeAreaType](ts-appendix-enums.md#hovermodeareatype13) | No  | Display area of the dialog box in the hover state.<br>Default value: **HoverModeAreaType.BOTTOM_SCREEN**|
62
63> **NOTE**
64>
65> - Pressing the Back or ESC key closes the dialog box.
66> - If the dialog box reaches its maximum allowable height on the screen when avoiding the soft keyboard, it reduces its height to fit.
67>   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.
68> - 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.
69>
70> - Currently, ArkUI dialog boxes do not close automatically when you switch pages unless you manually call **close**. If you need a dialog box to close in sync with page navigation, consider using the **Navigation** component. For details, see the [page display mode: dialog mode](../../../ui/arkts-navigation-navigation.md#page-display-mode).
71
72## DismissDialogAction<sup>12+</sup>
73
74Provides information about the action to dismiss the dialog box.
75
76**Atomic service API**: This API can be used in atomic services since API version 12.
77
78**System capability**: SystemCapability.ArkUI.ArkUI.Full
79
80### Properties
81
82| Name   | Type                                                        | Readable| Writable| Description                                                        |
83| ------- | ------------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ |
84| 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.|
85| 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.|
86
87## CustomDialogController
88
89**Atomic service API**: This API can be used in atomic services since API version 11.
90
91### Objects to Import
92
93```ts
94dialogController : CustomDialogController | null = new CustomDialogController(CustomDialogControllerOptions)
95```
96> **NOTE**
97>
98> **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.
99
100### open
101open()
102
103Opens 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.
104
105**Atomic service API**: This API can be used in atomic services since API version 11.
106
107**System capability**: SystemCapability.ArkUI.ArkUI.Full
108
109
110### close
111close()
112
113**Atomic service API**: This API can be used in atomic services since API version 11.
114
115**System capability**: SystemCapability.ArkUI.ArkUI.Full
116
117
118Closes the custom dialog box. If the dialog box is closed, this API does not take effect.
119
120## Example
121
122### Example 1
123
124```ts
125// xxx.ets
126@CustomDialog
127struct CustomDialogExampleTwo {
128  controllerTwo?: CustomDialogController
129  build() {
130    Column() {
131      Text('I'm the second dialog box')
132        .fontSize(30)
133        .height(100)
134      Button('Close Second Dialog Box')
135        .onClick(() => {
136          if (this.controllerTwo != undefined) {
137            this.controllerTwo.close()
138          }
139        })
140        .margin(20)
141    }
142  }
143}
144@CustomDialog
145@Component
146struct CustomDialogExample {
147  @Link textValue: string
148  @Link inputValue: string
149  dialogControllerTwo: CustomDialogController | null = new CustomDialogController({
150    builder: CustomDialogExampleTwo(),
151    alignment: DialogAlignment.Bottom,
152    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
153      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
154      console.log("dialog onWillDismiss")
155      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
156        dismissDialogAction.dismiss()
157      }
158      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
159        dismissDialogAction.dismiss()
160      }
161    },
162    offset: { dx: 0, dy: -25 } })
163  controller?: CustomDialogController
164  // 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.
165  cancel: () => void = () => {
166  }
167  confirm: () => void = () => {
168  }
169
170  build() {
171    Column() {
172      Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
173      TextInput({ placeholder: '', text: this.textValue }).height(60).width('90%')
174        .onChange((value: string) => {
175          this.textValue = value
176        })
177      Text('Are you sure you want to change the text?').fontSize(16).margin({ bottom: 10 })
178      Flex({ justifyContent: FlexAlign.SpaceAround }) {
179        Button('No')
180          .onClick(() => {
181            if (this.controller != undefined) {
182              this.controller.close()
183              this.cancel()
184            }
185          }).backgroundColor(0xffffff).fontColor(Color.Black)
186        Button('OK')
187          .onClick(() => {
188            if (this.controller != undefined) {
189              this.inputValue = this.textValue
190              this.controller.close()
191              this.confirm()
192            }
193          }).backgroundColor(0xffffff).fontColor(Color.Red)
194      }.margin({ bottom: 10 })
195
196      Button('Open Second Dialog Box')
197        .onClick(() => {
198          if (this.dialogControllerTwo != null) {
199            this.dialogControllerTwo.open()
200          }
201        })
202        .margin(20)
203    }.borderRadius(10)
204    // When using the border or cornerRadius attribute, use it together with the borderRadius attribute.
205  }
206}
207@Entry
208@Component
209struct CustomDialogUser {
210  @State textValue: string = ''
211  @State inputValue: string = 'click me'
212  dialogController: CustomDialogController | null = new CustomDialogController({
213    builder: CustomDialogExample({
214      cancel: ()=> { this.onCancel() },
215      confirm: ()=> { this.onAccept() },
216      textValue: $textValue,
217      inputValue: $inputValue
218    }),
219    cancel: this.exitApp,
220    autoCancel: true,
221    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
222      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
223      console.log("dialog onWillDismiss")
224      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
225        dismissDialogAction.dismiss()
226      }
227      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
228        dismissDialogAction.dismiss()
229      }
230    },
231    alignment: DialogAlignment.Bottom,
232    offset: { dx: 0, dy: -20 },
233    gridCount: 4,
234    customStyle: false,
235    cornerRadius: 10,
236  })
237
238  // Set dialogController to null when the custom component is about to be destroyed.
239  aboutToDisappear() {
240    this.dialogController = null // Set dialogController to null.
241  }
242
243  onCancel() {
244    console.info('Callback when the first button is clicked')
245  }
246
247  onAccept() {
248    console.info('Callback when the second button is clicked')
249  }
250
251  exitApp() {
252    console.info('Click the callback in the blank area')
253  }
254  build() {
255    Column() {
256      Button(this.inputValue)
257        .onClick(() => {
258          if (this.dialogController != null) {
259            this.dialogController.open()
260          }
261        }).backgroundColor(0x317aff)
262    }.width('100%').margin({ top: 5 })
263  }
264}
265```
266
267![en-us_image_custom](figures/en-us_image_custom.gif)
268
269### Example 2
270
271```ts
272// xxx.ets
273@CustomDialog
274struct CustomDialogExample {
275  controller?: CustomDialogController
276  cancel: () => void = () => {
277  }
278  confirm: () => void = () => {
279  }
280  build() {
281    Column() {
282      Text('Dialog box outside the main window')
283        .fontSize(30)
284        .height(100)
285      Button('Close')
286        .onClick(() => {
287          if (this.controller != undefined) {
288            this.controller.close()
289          }
290        })
291        .margin(20)
292    }
293  }
294}
295@Entry
296@Component
297struct CustomDialogUser {
298  dialogController: CustomDialogController | null = new CustomDialogController({
299    builder: CustomDialogExample({
300      cancel: ()=> { this.onCancel() },
301      confirm: ()=> { this.onAccept() }
302    }),
303    cancel: this.existApp,
304    autoCancel: true,
305    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
306      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
307      console.log("dialog onWillDismiss")
308      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
309        dismissDialogAction.dismiss()
310      }
311      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
312        dismissDialogAction.dismiss()
313      }
314    },
315    alignment: DialogAlignment.Center,
316    offset: { dx: 0, dy: -20 },
317    gridCount: 4,
318    showInSubWindow: true,
319    isModal: true,
320    customStyle: false,
321    cornerRadius: 10,
322  })
323  // Set dialogController to null when the custom component is about to be destroyed.
324  aboutToDisappear() {
325    this.dialogController = null // Set dialogController to null.
326  }
327
328  onCancel() {
329    console.info('Callback when the first button is clicked')
330  }
331
332  onAccept() {
333    console.info('Callback when the second button is clicked')
334  }
335
336  existApp() {
337    console.info('Click the callback in the blank area')
338  }
339
340  build() {
341    Column() {
342      Button('Click Me')
343        .onClick(() => {
344          if (this.dialogController != null) {
345            this.dialogController.open()
346          }
347        }).backgroundColor(0x317aff)
348    }.width('100%').margin({ top: 5 })
349  }
350}
351```
352
353![en-us_image_custom-showinsubwindow](figures/en-us_image_custom-showinsubwindow.jpg)
354
355### Example 3
356This example demonstrates how to set styles of a custom dialog box, including the width, height, background color, and shadow.
357```ts
358// xxx.ets
359@CustomDialog
360struct CustomDialogExample {
361  controller?: CustomDialogController
362  cancel: () => void = () => {
363  }
364  confirm: () => void = () => {
365  }
366  build() {
367    Column() {
368      Text('This is a custom dialog box')
369        .fontSize(30)
370        .height(100)
371      Button('Close')
372        .onClick(() => {
373          if (this.controller != undefined) {
374            this.controller.close()
375          }
376        })
377        .margin(20)
378    }
379  }
380}
381@Entry
382@Component
383struct CustomDialogUser {
384  dialogController: CustomDialogController | null = new CustomDialogController({
385    builder: CustomDialogExample({
386      cancel: ()=> { this.onCancel() },
387      confirm: ()=> { this.onAccept() }
388    }),
389    cancel: this.existApp,
390    autoCancel: true,
391    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
392      console.info("reason=" + JSON.stringify(dismissDialogAction.reason))
393      console.log("dialog onWillDismiss")
394      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
395        dismissDialogAction.dismiss()
396      }
397      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
398        dismissDialogAction.dismiss()
399      }
400    },
401    alignment: DialogAlignment.Center,
402    offset: { dx: 0, dy: -20 },
403    customStyle: false,
404    cornerRadius: 20,
405    width: 300,
406    height: 200,
407    borderWidth: 1,
408    borderStyle: BorderStyle.Dashed,// borderStyle must be used with borderWidth in pairs.
409    borderColor: Color.Blue,// borderColor must be used with borderWidth in pairs.
410    backgroundColor: Color.White,
411    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
412  })
413  // Set dialogController to null when the custom component is about to be destroyed.
414  aboutToDisappear() {
415    this.dialogController = null // Set dialogController to null.
416  }
417
418  onCancel() {
419    console.info('Callback when the first button is clicked')
420  }
421
422  onAccept() {
423    console.info('Callback when the second button is clicked')
424  }
425
426  existApp() {
427    console.info('Click the callback in the blank area')
428  }
429
430  build() {
431    Column() {
432      Button('Click Me')
433        .onClick(() => {
434          if (this.dialogController != null) {
435            this.dialogController.open()
436          }
437        }).backgroundColor(0x317aff)
438    }.width('100%').margin({ top: 5 })
439  }
440}
441```
442
443![en-us_image_custom_style](figures/en-us_image_custom_style.gif)
444
445### Example 4
446
447This example demonstrates how to set the layout area of a dialog box in the hover state on a foldable device.
448
449```ts
450@CustomDialog
451@Component
452struct CustomDialogExample {
453  @Link textValue: string;
454  @Link inputValue: string;
455  controller?: CustomDialogController;
456
457  build() {
458    Column() {
459      Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
460      TextInput({ placeholder: '', text: this.textValue }).height(60).width('90%')
461        .onChange((value: string) => {
462          this.textValue = value;
463        })
464      Text('Are you sure you want to change the text?').fontSize(16).margin({ bottom: 10 })
465      Flex({ justifyContent: FlexAlign.SpaceAround }) {
466        Button('No')
467          .onClick(() => {
468            if (this.controller != undefined) {
469              this.controller.close();
470            }
471          }).backgroundColor(0xffffff).fontColor(Color.Black)
472        Button('OK')
473          .onClick(() => {
474            if (this.controller != undefined) {
475              this.inputValue = this.textValue;
476              this.controller.close();
477            }
478          }).backgroundColor(0xffffff).fontColor(Color.Red)
479      }.margin({ bottom: 10 })
480
481      Button('Open Second Dialog Box')
482        .margin(20)
483    }.borderRadius(10)
484    // When using the border or cornerRadius attribute, use it together with the borderRadius attribute.
485  }
486}
487@Entry
488@Component
489struct CustomDialogUser {
490  @State textValue: string = '';
491  @State inputValue: string = 'click me';
492  dialogController: CustomDialogController | null = new CustomDialogController({
493    builder: CustomDialogExample({
494      textValue: $textValue,
495      inputValue: $inputValue
496    }),
497    cancel: this.exitApp,
498    autoCancel: true,
499    onWillDismiss: (dismissDialogAction: DismissDialogAction)=> {
500      console.info("reason=" + JSON.stringify(dismissDialogAction.reason));
501      console.log("dialog onWillDismiss");
502      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
503        dismissDialogAction.dismiss();
504      }
505      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
506        dismissDialogAction.dismiss();
507      }
508    },
509    alignment: DialogAlignment.Bottom,
510    offset: { dx: 0, dy: -20 },
511    gridCount: 4,
512    customStyle: false,
513    cornerRadius: 10,
514    enableHoverMode: true,
515    hoverModeArea: HoverModeAreaType.TOP_SCREEN
516  })
517
518  // Set dialogController to null when the custom component is about to be destroyed.
519  aboutToDisappear() {
520    this.dialogController = null; // Set dialogController to null.
521  }
522
523  exitApp() {
524    console.info('Click the callback in the blank area');
525  }
526
527  build() {
528    Column() {
529      Button(this.inputValue)
530        .onClick(() => {
531          if (this.dialogController != null) {
532            this.dialogController.open();
533          }
534        }).backgroundColor(0x317aff)
535    }.width('100%').margin({ top: 5 })
536  }
537}
538```
539
540![en-us_image_custom](figures/en-us_image_custom_hovermode.gif)
541