1# Basic Custom Dialog Box (CustomDialog) (Not Recommended)
2A custom dialog box is a dialog box you customize by using APIs of the **CustomDialogController** class. It can be used for user interactions, showing ads, award announcements, alerts, software update notifications, and more. For details, see [Custom Dialog Box](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md).
3
4> **NOTE**
5>
6> In ArkUI, dialog boxes do not close automatically when you switch pages unless you manually call **close**. To enable a dialog box to be dismissed during page navigation, consider using the **Navigation** component. For details, see the [page display mode: dialog mode](arkts-navigation-navigation.md#page-display-mode).
7
8You can specify the modality of a dialog box by setting [isModal](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md#customdialogcontrolleroptions). A dialog box is modal if **isModal** is set to **true** and non-modal otherwise.
9
10## Creating a Custom Dialog Box
11
121. Use the \@CustomDialog decorator to create a custom dialog box. You can define the content of the dialog box within the decorator. Note that **CustomDialogController** must be defined in @Component.
13
14   ```ts
15   @CustomDialog
16   struct CustomDialogExample {
17     controller: CustomDialogController = new CustomDialogController({
18       builder: CustomDialogExample({}),
19     })
20
21     build() {
22       Column() {
23         Text('I am content')
24           .fontSize(20)
25           .margin({ top: 10, bottom: 10 })
26       }
27     }
28   }
29   ```
302. Create a builder that is bound to the decorator.
31
32   ```ts
33    @Entry
34    @Component
35    struct CustomDialogUser {
36      dialogController: CustomDialogController = new CustomDialogController({
37        builder: CustomDialogExample(),
38      })
39    }
40   ```
413. Click the component bound to the **onClick** event to display the dialog box.
42
43   ```ts
44   @Entry
45   @Component
46   struct CustomDialogUser {
47     dialogController: CustomDialogController = new CustomDialogController({
48       builder: CustomDialogExample(),
49     })
50
51     build() {
52       Column() {
53         Button('click me')
54           .onClick(() => {
55             this.dialogController.open()
56           })
57       }.width('100%').margin({ top: 5 })
58     }
59   }
60   ```
61
62   ![en-us_image_0000001562700493](figures/en-us_image_0000001562700493.png)
63
64## Implementing Interaction with the Custom Dialog Box
65
66Custom dialog boxes can be used for data interactions to complete a series of operations.
67
681. Add buttons in the \@CustomDialog decorator structure and add data functions.
69
70   ```ts
71   @CustomDialog
72   struct CustomDialogExample {
73     cancel?: () => void
74     confirm?: () => void
75     controller: CustomDialogController
76
77     build() {
78       Column() {
79         Text('I am content').fontSize(20).margin({ top: 10, bottom: 10 })
80         Flex({ justifyContent: FlexAlign.SpaceAround }) {
81           Button('Cancel')
82             .onClick(() => {
83               this.controller.close()
84               if (this.cancel) {
85                 this.cancel()
86               }
87             }).backgroundColor(0xffffff).fontColor(Color.Black)
88           Button('Obtain')
89             .onClick(() => {
90               this.controller.close()
91               if (this.confirm) {
92                 this.confirm()
93               }
94             }).backgroundColor(0xffffff).fontColor(Color.Red)
95         }.margin({ bottom: 10 })
96       }
97     }
98   }
99   ```
1002. Receive the page in the builder and create corresponding function operations.
101
102   ```ts
103   @Entry
104   @Component
105   struct CustomDialogUser {
106     dialogController: CustomDialogController = new CustomDialogController({
107       builder: CustomDialogExample({
108         cancel: ()=> { this.onCancel() },
109         confirm: ()=> { this.onAccept() },
110       }),
111     })
112
113     onCancel() {
114       console.info('Callback when the first button is clicked')
115     }
116
117     onAccept() {
118       console.info('Callback when the second button is clicked')
119     }
120
121     build() {
122       Column() {
123         Button('click me')
124           .onClick(() => {
125             this.dialogController.open()
126           })
127       }.width('100%').margin({ top: 5 })
128     }
129   }
130   ```
131
132   ![en-us_image_0000001511421320](figures/en-us_image_0000001511421320.png)
133
134   3. Use the button in the dialog box to implement route redirection and obtain the parameters passed in from the redirection target page.
135
136   ```ts
137   // Index.ets
138   @CustomDialog
139   struct CustomDialogExample {
140     @Link textValue: string
141     controller?: CustomDialogController
142     cancel: () => void = () => {
143     }
144     confirm: () => void = () => {
145     }
146
147     build() {
148       Column({ space: 20 }) {
149         if (this.textValue != '') {
150           Text(`Content of the second page: ${this.textValue}`)
151             .fontSize(20)
152         } else {
153           Text('Obtain the content of the second page?')
154             .fontSize(20)
155         }
156         Flex({ justifyContent: FlexAlign.SpaceAround }) {
157           Button('Cancel')
158             .onClick(() => {
159               if (this.controller != undefined) {
160                 this.controller.close()
161                 this.cancel()
162               }
163             }).backgroundColor(0xffffff).fontColor(Color.Black)
164           Button('Obtain')
165             .onClick(() => {
166               if (this.controller != undefined && this.textValue != '') {
167                 this.controller.close()
168               } else if (this.controller != undefined) {
169                 this.getUIContext().getRouter().pushUrl({
170                   url: 'pages/Index2'
171                 })
172                 this.controller.close()
173               }
174             }).backgroundColor(0xffffff).fontColor(Color.Red)
175         }.margin({ bottom: 10 })
176       }.borderRadius(10).padding({ top: 20 })
177     }
178   }
179
180   @Entry
181   @Component
182   struct CustomDialogUser {
183     @State textValue: string = ''
184     dialogController: CustomDialogController | null = new CustomDialogController({
185       builder: CustomDialogExample({
186         cancel: () => {
187           this.onCancel()
188         },
189         confirm: () => {
190           this.onAccept()
191         },
192         textValue: $textValue
193       })
194     })
195
196     // Set dialogController to null when the custom component is about to be destroyed.
197     aboutToDisappear() {
198       this.dialogController = null // Set dialogController to null.
199     }
200
201     onPageShow() {
202       const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // Obtain the passed parameter object.
203       if (params) {
204         this.dialogController?.open()
205         this.textValue = params.info as string; // Obtain the value of the id attribute.
206       }
207     }
208
209     onCancel() {
210       console.info('Callback when the first button is clicked')
211     }
212
213     onAccept() {
214       console.info('Callback when the second button is clicked')
215     }
216
217     exitApp() {
218       console.info('Click the callback in the blank area')
219     }
220
221     build() {
222       Column() {
223         Button('click me')
224           .onClick(() => {
225             if (this.dialogController != null) {
226               this.dialogController.open()
227             }
228           }).backgroundColor(0x317aff)
229       }.width('100%').margin({ top: 5 })
230     }
231   }
232   ```
233
234   ```ts
235   // Index2.ets
236   @Entry
237   @Component
238   struct Index2 {
239     @State message: string =' Back';
240     build() {
241       Column() {
242         Button(this.message)
243           .fontSize(50)
244           .fontWeight(FontWeight.Bold).onClick(() => {
245           this.getUIContext().getRouter().back({
246             url: 'pages/Index',
247             params: {
248               info: 'Hello World'
249             }
250           });
251         })
252       }.width('100%').height('100%').margin({ top: 20 })
253     }
254   }
255   ```
256
257   ![DialogRouter](figures/DialogRouter.gif)
258
259## Defining the Custom Dialog Box Animation
260
261You can define the custom dialog box animation, including its duration and speed, through **openAnimation**.
262
263```ts
264@CustomDialog
265struct CustomDialogExample {
266  controller?: CustomDialogController
267
268  build() {
269    Column() {
270      Text('Whether to change a text?').fontSize(16).margin({ bottom: 10 })
271    }
272  }
273}
274
275@Entry
276@Component
277struct CustomDialogUser {
278  @State textValue: string = ''
279  @State inputValue: string = 'click me'
280  dialogController: CustomDialogController | null = new CustomDialogController({
281    builder: CustomDialogExample(),
282    openAnimation: {
283      duration: 1200,
284      curve: Curve.Friction,
285      delay: 500,
286      playMode: PlayMode.Alternate,
287      onFinish: () => {
288        console.info('play end')
289      }
290    },
291    autoCancel: true,
292    alignment: DialogAlignment.Bottom,
293    offset: { dx: 0, dy: -20 },
294    gridCount: 4,
295    customStyle: false,
296    backgroundColor: 0xd9ffffff,
297    cornerRadius: 10,
298  })
299
300  // Set dialogController to null when the custom component is about to be destroyed.
301  aboutToDisappear() {
302    this.dialogController = null // Set dialogController to null.
303  }
304
305  build() {
306    Column() {
307      Button(this.inputValue)
308        .onClick(() => {
309          if (this.dialogController != null) {
310            this.dialogController.open()
311          }
312        }).backgroundColor(0x317aff)
313    }.width('100%').margin({ top: 5 })
314  }
315}
316```
317
318![openAnimator](figures/openAnimator.gif)
319
320## Defining the Custom Dialog Box Style
321
322You can set style parameters, such as the width, height, background color, and shadow, for a custom dialog box.
323
324```ts
325@CustomDialog
326struct CustomDialogExample {
327  controller?: CustomDialogController
328
329  build() {
330    Column() {
331      Text('I am content').fontSize(16).margin({ bottom: 10 })
332    }
333  }
334}
335
336@Entry
337@Component
338struct CustomDialogUser {
339  @State textValue: string = ''
340  @State inputValue: string = 'Click Me'
341  dialogController: CustomDialogController | null = new CustomDialogController({
342    builder: CustomDialogExample(),
343    autoCancel: true,
344    alignment: DialogAlignment.Center,
345    offset: { dx: 0, dy: -20 },
346    gridCount: 4,
347    customStyle: false,
348    backgroundColor: 0xd9ffffff,
349    cornerRadius: 20,
350    width: '80%',
351    height: '100px',
352    borderWidth: 1,
353    borderStyle: BorderStyle.Dashed,// borderStyle must be used with borderWidth in pairs.
354    borderColor: Color.Blue,// borderColor must be used with borderWidth in pairs.
355    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
356  })
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  build() {
364    Column() {
365      Button(this.inputValue)
366        .onClick(() => {
367          if (this.dialogController != null) {
368            this.dialogController.open()
369          }
370        }).backgroundColor(0x317aff)
371    }.width('100%').margin({ top: 5 })
372  }
373}
374```
375
376![custom_style](figures/custom_style.gif)
377
378## Nesting a Custom Dialog Box
379
380To nest a dialog box (dialog 2) inside another dialog box (dialog 1), it is recommended that you define dialog 2 within the parent component of dialog 1 so that you can then open dialog 2 through the callback sent from the parent component to dialog 1.
381
382```ts
383@CustomDialog
384struct CustomDialogExampleTwo {
385  controllerTwo?: CustomDialogController
386  @State message: string = "I'm the second dialog box."
387  @State showIf: boolean = false;
388  build() {
389    Column() {
390      if (this.showIf) {
391        Text("Text")
392          .fontSize(30)
393          .height(100)
394      }
395      Text(this.message)
396        .fontSize(30)
397        .height(100)
398      Button("Create Text")
399        .onClick(()=>{
400          this.showIf = true;
401        })
402      Button('Close Second Dialog Box')
403        .onClick(() => {
404          if (this.controllerTwo != undefined) {
405            this.controllerTwo.close()
406          }
407        })
408        .margin(20)
409    }
410  }
411}
412@CustomDialog
413struct CustomDialogExample {
414  openSecondBox?: ()=>void
415  controller?: CustomDialogController
416
417  build() {
418    Column() {
419      Button('Open Second Dialog Box and Close This Box')
420        .onClick(() => {
421          this.controller!.close();
422          this.openSecondBox!();
423        })
424        .margin(20)
425    }.borderRadius(10)
426  }
427}
428@Entry
429@Component
430struct CustomDialogUser {
431  @State inputValue: string = 'Click Me'
432  dialogController: CustomDialogController | null = new CustomDialogController({
433    builder: CustomDialogExample({
434      openSecondBox: ()=>{
435        if (this.dialogControllerTwo != null) {
436          this.dialogControllerTwo.open()
437        }
438      }
439    }),
440    cancel: this.exitApp,
441    autoCancel: true,
442    alignment: DialogAlignment.Bottom,
443    offset: { dx: 0, dy: -20 },
444    gridCount: 4,
445    customStyle: false
446  })
447  dialogControllerTwo: CustomDialogController | null = new CustomDialogController({
448    builder: CustomDialogExampleTwo(),
449    alignment: DialogAlignment.Bottom,
450    offset: { dx: 0, dy: -25 } })
451
452  aboutToDisappear() {
453    this.dialogController = null
454    this.dialogControllerTwo = null
455  }
456
457  onCancel() {
458    console.info('Callback when the first button is clicked')
459  }
460
461  onAccept() {
462    console.info('Callback when the second button is clicked')
463  }
464
465  exitApp() {
466    console.info('Click the callback in the blank area')
467  }
468  build() {
469    Column() {
470      Button(this.inputValue)
471        .onClick(() => {
472          if (this.dialogController != null) {
473            this.dialogController.open()
474          }
475        }).backgroundColor(0x317aff)
476    }.width('100%').margin({ top: 5 })
477  }
478}
479```
480
481![nested_dialog](figures/nested_dialog.gif)
482
483If you define dialog 2 within dialog 1 instead, because of the parent-child relationship that exists between custom dialog boxes in terms of state management, you will not be able to create any component in dialog 2 once dialog 1 is destroyed (closed).
484
485