1# \@Builder Decorator: Custom Builder Function
2
3ArkUI provides the \@Builder decorator that is a lightweight UI element reuse mechanism. This custom component has a fixed internal UI structure and passes the data only to the user. You can abstract reused UI elements into a method and call the method in the **build** method.
4
5For simplicity, here we refer to an \@Builder decorated function also as a custom builder function.
6
7
8> **NOTE**
9>
10> This decorator can be used in ArkTS widgets since API version 9.
11>
12> This decorator can be used in atomic services since API version 11.
13
14
15## Rules of Use
16
17### Private Custom Builder Function
18
19Syntax:
20
21```ts
22@Builder MyBuilderFunction() {}
23```
24
25Usage:
26
27```ts
28this.MyBuilderFunction()
29```
30
31- You can define one or more @Builder decorated methods in a custom component. Such a method is considered as a private, special type of member function of the component.
32
33- Private custom builder functions can be called in custom components, **build()**, and other custom builder functions.
34
35- Inside the custom builder function body, **this** refers to the owning component. Component state variables are accessible from within the custom builder function implementation. Using **this** to access the custom components' state variables is recommended over parameter passing.
36
37
38### Global Custom Builder Function
39
40Syntax:
41
42```ts
43@Builder function MyGlobalBuilderFunction() { ... }
44```
45
46Usage:
47
48```ts
49MyGlobalBuilderFunction()
50```
51
52- Use of a global custom builder function is recommended if no own state is involved.
53
54- Global custom builder functions can be called in **build()** and other custom builder functions.
55
56
57## Parameter Passing Rules
58
59For custom builder functions, parameters can be passed [by value](#by-value-parameter-passing) and [by reference](#by-reference-parameter-passing). Both of them must comply with the following rules:
60
61- The parameter type must be the same as the declared parameter type. The **undefined** or **null** constants as well as expressions evaluating to these values are not allowed.
62
63- All parameters must be immutable inside the custom builder function.
64
65- The custom builder function body follows the same [syntax rules](arkts-create-custom-components.md#build-function) as **build()**.
66
67- Parameters are passed by value in all cases except when only one parameter is passed in and the parameter needs to be directly passed to the object literal.
68
69
70### By-Reference Parameter Passing
71
72In by-reference parameter passing, state variables can be passed, and the change of these state variables causes the UI re-rendering in the \@Builder decorated method.
73
74```ts
75class Tmp {
76  paramA1: string = ''
77}
78
79@Builder function overBuilder(params: Tmp) {
80  Row() {
81    Text(`UseStateVarByReference: ${params.paramA1} `)
82  }
83}
84@Entry
85@Component
86struct Parent {
87  @State label: string = 'Hello';
88  build() {
89    Column() {
90      // When the overBuilder component is called in the parent component,
91      // pass this.label to the overBuilder component by reference.
92      overBuilder({ paramA1: this.label })
93      Button('Click me').onClick(() => {
94        // After you click "Click me", the UI text changes from "Hello" to "ArkUI".
95        this.label = 'ArkUI';
96      })
97    }
98  }
99}
100```
101
102When parameters are passed by reference, if a custom component is called within the \@Builder method, ArkUI provides [$$](arkts-two-way-sync.md) as the paradigm for passing parameters by reference.
103
104```ts
105class Tmp {
106  paramA1: string = ''
107}
108
109@Builder function overBuilder($$: Tmp) {
110  Row() {
111    Column() {
112      Text(`overBuilder===${$$.paramA1}`)
113      HelloComponent({message: $$.paramA1})
114    }
115  }
116}
117
118@Component
119struct HelloComponent {
120  @Prop message: string;
121
122  build() {
123    Row() {
124      Text(`HelloComponent===${this.message}`)
125    }
126  }
127}
128
129@Entry
130@Component
131struct Parent {
132  @State label: string = 'Hello';
133  build() {
134    Column() {
135      // When the overBuilder component is called in the parent component,
136      // pass this.label to the overBuilder component by reference.
137      overBuilder({paramA1: this.label})
138      Button('Click me').onClick(() => {
139        // After you click "Click me", the UI text changes from "Hello" to "ArkUI".
140        this.label = 'ArkUI';
141      })
142    }
143  }
144}
145```
146
147### By-Value Parameter Passing
148
149By default, parameters in the \@Builder decorated functions are passed by value. In this case, when the passed parameter is a state variable, the change of the state variable does not cause UI re-rendering in the \@Builder decorated function. Therefore, when passing state variables, you are advised to use [by-reference parameter passing](#by-reference-parameter-passing).
150
151```ts
152@Builder function overBuilder(paramA1: string) {
153  Row() {
154    Text(`UseStateVarByValue: ${paramA1} `)
155  }
156}
157@Entry
158@Component
159struct Parent {
160  @State label: string = 'Hello';
161  build() {
162    Column() {
163      overBuilder(this.label)
164    }
165  }
166}
167```
168
169In the way of passing parameters by value, the @ObservedV2 and @Trace decorators can be used together in the @ComponentV2 decorated custom component to re-render the UI.
170
171[Positive Example]
172
173In @ComponentV2, only the @ObservedV2 decorated **ParamTmp** class and the @Trace decorated **count** property can trigger the UI re-render.
174
175```ts
176@ObservedV2
177class ParamTmp {
178  @Trace count : number = 0;
179}
180
181@Builder
182function renderText(param: ParamTmp) {
183  Column() {
184    Text(`param : ${param.count}`)
185      .fontSize(20)
186      .fontWeight(FontWeight.Bold)
187  }
188}
189
190@Builder
191function renderMap(paramMap: Map<string,number>) {
192  Text(`paramMap : ${paramMap.get('name')}`)
193    .fontSize(20)
194    .fontWeight(FontWeight.Bold)
195}
196
197@Builder
198function renderSet(paramSet: Set<number>) {
199  Text(`paramSet : ${paramSet.size}`)
200    .fontSize(20)
201    .fontWeight(FontWeight.Bold)
202}
203
204@Builder
205function renderNumberArr(paramNumArr: number[]) {
206  Text(`paramNumArr : ${paramNumArr[0]}`)
207    .fontSize(20)
208    .fontWeight(FontWeight.Bold)
209}
210
211@Entry
212@ComponentV2
213struct PageBuilder {
214  @Local builderParams: ParamTmp = new ParamTmp();
215  @Local map_value: Map<string,number> = new Map();
216  @Local set_value: Set<number> = new Set([0]);
217  @Local numArr_value: number[] = [0];
218  private progressTimer: number = -1;
219
220  aboutToAppear(): void {
221    this.progressTimer = setInterval(() => {
222      if (this.builderParams.count < 100) {
223        this.builderParams.count += 5;
224        this.map_value.set('name', this.builderParams.count);
225        this.set_value.add(this.builderParams.count);
226        this.numArr_value[0] = this.builderParams.count;
227      } else {
228        clearInterval(this.progressTimer)
229      }
230    }, 500);
231  }
232
233  @Builder
234  localBuilder() {
235    Column() {
236      Text(`localBuilder : ${this.builderParams.count}`)
237        .fontSize(20)
238        .fontWeight(FontWeight.Bold)
239    }
240  }
241
242  build() {
243    Column() {
244      this.localBuilder()
245      Text(`builderParams :${this.builderParams.count}`)
246        .fontSize(20)
247        .fontWeight(FontWeight.Bold)
248      renderText(this.builderParams)
249      renderText({ count: this.builderParams.count })
250      renderMap(this.map_value)
251      renderSet(this.set_value)
252      renderNumberArr(this.numArr_value)
253    }
254    .width('100%')
255    .height('100%')
256  }
257}
258```
259
260[Negative Example]
261
262In the @ComponentV2 decorated custom component, the use of simple data types cannot trigger UI re-render.
263
264```ts
265@ObservedV2
266class ParamTmp {
267  @Trace count : number = 0;
268}
269
270@Builder
271function renderNumber(paramNum: number) {
272  Text(`paramNum : ${paramNum}`)
273    .fontSize(30)
274    .fontWeight(FontWeight.Bold)
275}
276
277@Entry
278@ComponentV2
279struct PageBuilder {
280  @Local class_value: ParamTmp = new ParamTmp();
281  // Using simple data type cannot trigger UI re-render
282  @Local num_value: number = 0;
283  private progressTimer: number = -1;
284
285  aboutToAppear(): void {
286    this.progressTimer = setInterval(() => {
287      if (this.class_value.count < 100) {
288        this.class_value.count += 5;
289        this.num_value += 5;
290      } else {
291        clearInterval(this.progressTimer)
292      }
293    }, 500);
294  }
295
296  build() {
297    Column() {
298      renderNumber(this.num_value)
299    }
300    .width('100%')
301    .height('100%')
302    .padding(50)
303  }
304}
305```
306
307## Constraints
308
3091. Parameter values cannot be changed in \@Builder decorated functions. Otherwise, the framework throws a runtime error. You can change the parameters in the \@Builder decorated custom components.
310
311```ts
312interface Temp {
313  paramA: string;
314}
315
316@Builder function overBuilder($$: Temp) {
317  Row() {
318    Column() {
319      Button(`overBuilder === ${$$.paramA}`)
320        .onClick(() => {
321          // Incorrect format. Parameter values cannot be changed in the function decorated by @Builder.
322          $$.paramA = 'Yes';
323      })
324    }
325  }
326}
327
328@Entry
329@Component
330struct Parent {
331  @State label: string = 'Hello';
332
333  build() {
334    Column() {
335      overBuilder({paramA: this.label})
336      Button('click me')
337        .onClick(() => {
338          this.label = 'ArkUI';
339        })
340    }
341  }
342}
343```
344
3452. The \@Builder triggers dynamic UI rendering for only when parameters are passed in by reference. Only one parameter can be passed.
346
3473. If the \@Builder passes in two or more parameters, dynamic UI rendering is not triggered.
348
3494. If the \@Builder passes in parameters by value and by reference, dynamic UI rendering is not triggered.
350
3515. \@Builder parameters must be passed in one by one in the form of object literals to trigger dynamic UI rendering.
352
353
354## Use Scenarios
355
356### Using Custom Builder Function in Custom Component
357
358Create a private \@Builder method, call this method by using **this.builder()** in **Column**, and change the content of **builder_value** through the **aboutToAppear** lifecycle function and Button click event to dynamically render the UI.
359
360```ts
361@Entry
362@Component
363struct PrivateBuilder {
364  @State builder_value: string = 'Hello';
365
366  @Builder builder() {
367    Column(){
368      Text(this.builder_value)
369        .fontSize(30)
370        .fontWeight(FontWeight.Bold)
371    }
372  }
373
374  aboutToAppear(): void {
375    setTimeout(() => {
376      this.builder_value = 'Hello World';
377    },3000)
378  }
379
380  build() {
381    Row() {
382      Column() {
383        Text(this.builder_value)
384          .fontSize(30)
385          .fontWeight(FontWeight.Bold)
386        this.builder()
387        Button('Click to change builder_value')
388          .onClick(() => {
389            this.builder_value = 'builder_value clicked'
390          })
391      }
392    }
393  }
394}
395```
396
397### Using Global Custom Builder Function
398
399Create a global \@Builder method and call this method by using **overBuilder()** in **Column**. Pass the simple type or complex type parameters in the form of object literals, value changes will trigger UI re-rendering.
400
401```ts
402class ChildTmp {
403  val: number = 1;
404}
405
406class Tmp {
407  str_value: string = 'Hello';
408  num_value: number = 0;
409  tmp_value: ChildTmp = new ChildTmp();
410  arrayTmp_value: Array<ChildTmp> = [];
411}
412
413@Builder function overBuilder(param: Tmp) {
414  Column() {
415    Text(`str_value: ${param.str_value}`)
416    Text(`num_value: ${param.num_value}`)
417    Text(`tmp_value: ${param.tmp_value.val}`)
418    ForEach(param.arrayTmp_value, (item: ChildTmp) => {
419      Text(`arrayTmp_value: ${item.val}`)
420    }, (item: ChildTmp) => JSON.stringify(item))
421  }
422}
423
424@Entry
425@Component
426struct Parent {
427  @State objParam: Tmp = new Tmp();
428  build() {
429    Column() {
430      Text('Render the UI by calling the @Builder')
431        .fontSize(20)
432      overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value,
433       tmp_value: this.objParam.tmp_value, arrayTmp_value: this.objParam.arrayTmp_value})
434      Line()
435        .width('100%')
436        .height(10)
437        .backgroundColor('#000000').margin(10)
438      Button('Click to change parameter').onClick(() => {
439        this.objParam.str_value = 'Hello World';
440        this.objParam.num_value = 1;
441        this.objParam.tmp_value.val = 8;
442        const child_value: ChildTmp = {
443          val: 2
444        }
445        this.objParam.arrayTmp_value.push(child_value)
446      })
447    }
448  }
449}
450```
451
452### Changing the Variables Decorated by the Decorator Triggers UI Re-rendering
453
454In this case, the decorator feature is used. The change of the listening value triggers UI re-rendering and parameters are not passed through the \@Builder.
455
456```ts
457class Tmp {
458  str_value: string = 'Hello';
459}
460
461@Entry
462@Component
463struct Parent {
464  @State objParam: Tmp = new Tmp();
465  @State label: string = 'World';
466
467  @Builder privateBuilder() {
468    Column() {
469      Text(`wrapBuilder str_value: ${this.objParam.str_value}`)
470      Text(`wrapBuilder num: ${this.label}`)
471    }
472  }
473
474  build() {
475    Column() {
476      Text('Render the UI by calling the @Builder')
477        .fontSize(20)
478      this.privateBuilder()
479      Line()
480        .width('100%')
481        .height(10)
482        .backgroundColor('#000000').margin(10)
483      Button('Click to change parameter').onClick(() => {
484        this.objParam.str_value = 'str_value Hello World';
485        this.label = 'label Hello World'
486      })
487    }
488  }
489}
490```
491
492### Using the Global and Local @Builder to Pass in Parameters of the customBuilder Type
493
494```ts
495@Builder
496function overBuilder() {
497  Row() {
498    Text('Global Builder')
499      .fontSize(30)
500      .fontWeight(FontWeight.Bold)
501  }
502}
503
504@Entry
505@Component
506struct customBuilderDemo {
507  @State arr: number[] = [0, 1, 2, 3, 4];
508
509  @Builder privateBuilder() {
510    Row() {
511      Text('Local Builder')
512        .fontSize(30)
513        .fontWeight(FontWeight.Bold)
514    }
515  }
516
517  build() {
518    Column() {
519      List({ space: 10 }) {
520        ForEach(this.arr, (item: number) => {
521          ListItem(){
522            Text(`${item}`)
523              .width('100%')
524              .height(100)
525              .fontSize(16)
526              .textAlign(TextAlign.Center)
527              .borderRadius(10)
528              .backgroundColor(0xFFFFFF)
529          }
530            .swipeAction({
531              start: {
532                builder: overBuilder()
533              },
534              end: {
535                builder: () => { this.privateBuilder() }
536              }
537            })
538        }, (item: string) => JSON.stringify(item))
539      }
540    }
541  }
542}
543```
544
545### Nesting of Multi-layer \@Builder Method
546
547Call the custom components or other methods within \@Builder method. ArkUI provides [$$](arkts-two-way-sync.md) as a paradigm for passing parameters by reference.
548
549```ts
550class Tmp {
551  paramA1: string = '';
552}
553
554@Builder function parentBuilder($$: Tmp) {
555  Row() {
556    Column() {
557      Text(`parentBuilder===${$$.paramA1}`)
558        .fontSize(30)
559        .fontWeight(FontWeight.Bold)
560      HelloComponent({message: $$.paramA1})
561      childBuilder({paramA1: $$.paramA1})
562    }
563  }
564}
565
566@Component
567struct HelloComponent {
568  @Prop message: string = '';
569
570  build() {
571    Row() {
572      Text(`HelloComponent===${this.message}`)
573        .fontSize(30)
574        .fontWeight(FontWeight.Bold)
575    }
576  }
577}
578
579@Builder
580function childBuilder($$: Tmp) {
581  Row() {
582    Column() {
583      Text(`childBuilder===${$$.paramA1}`)
584        .fontSize(30)
585        .fontWeight(FontWeight.Bold)
586      HelloChildComponent({message: $$.paramA1})
587      grandsonBuilder({paramA1: $$.paramA1})
588    }
589  }
590}
591
592@Component
593struct HelloChildComponent {
594  @Prop message: string = '';
595  build() {
596    Row() {
597      Text(`HelloChildComponent===${this.message}`)
598        .fontSize(30)
599        .fontWeight(FontWeight.Bold)
600    }
601  }
602}
603
604@Builder function grandsonBuilder($$: Tmp) {
605  Row() {
606    Column() {
607      Text(`grandsonBuilder===${$$.paramA1}`)
608        .fontSize(30)
609        .fontWeight(FontWeight.Bold)
610      HelloGrandsonComponent({message: $$.paramA1})
611    }
612  }
613}
614
615@Component
616struct HelloGrandsonComponent {
617  @Prop message: string;
618  build() {
619    Row() {
620      Text(`HelloGrandsonComponent===${this.message}`)
621        .fontSize(30)
622        .fontWeight(FontWeight.Bold)
623    }
624  }
625}
626
627@Entry
628@Component
629struct Parent {
630  @State label: string = 'Hello';
631  build() {
632    Column() {
633      parentBuilder({paramA1: this.label})
634      Button('Click me').onClick(() => {
635        this.label = 'ArkUI';
636      })
637    }
638  }
639}
640```
641
642### Using \@Builder Functions Together with the Decorators in V2
643
644Call the global @Builder and local @Builder in the @ComponentV2 decorated custom component to change related variables, triggering UI re-renders.
645
646```ts
647@ObservedV2
648class Info {
649  @Trace name: string = '';
650  @Trace age: number = 0;
651}
652
653@Builder
654function overBuilder(param: Info) {
655  Column() {
656    Text('Global @Builder name :${param.name}`)
657      .fontSize(30)
658      .fontWeight(FontWeight.Bold)
659    Text('Global @Builder age :${param.age}`)
660      .fontSize(30)
661      .fontWeight(FontWeight.Bold)
662  }
663}
664
665@ComponentV2
666struct ChildPage {
667  @Require @Param childInfo: Info;
668  build() {
669    overBuilder({name: this.childInfo.name, age: this.childInfo.age})
670  }
671}
672
673@Entry
674@ComponentV2
675struct ParentPage {
676  info1: Info = { name: "Tom", age: 25 };
677  @Local info2: Info = { name: "Tom", age: 25 };
678
679  @Builder
680  privateBuilder() {
681    Column() {
682      Text('Local @Builder name :${this.info1.name}`)
683        .fontSize(30)
684        .fontWeight(FontWeight.Bold)
685      Text('Local @Builder age :${this.info1.age}`)
686        .fontSize(30)
687        .fontWeight(FontWeight.Bold)
688    }
689  }
690
691  build() {
692    Column() {
693      Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1
694        .fontSize(30)
695        .fontWeight(FontWeight.Bold)
696      this.privateBuilder() // Call the local @Builder.
697      Line()
698        .width('100%')
699        .height(10)
700        .backgroundColor('#000000').margin(10)
701      Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2
702        .fontSize(30)
703        .fontWeight(FontWeight.Bold)
704      overBuilder({ name: this.info2.name, age: this.info2.age}) // Call the global @Builder.
705      Line()
706        .width('100%')
707        .height(10)
708        .backgroundColor('#000000').margin(10)
709      Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1
710        .fontSize(30)
711        .fontWeight(FontWeight.Bold)
712      ChildPage ({childInfo: this.info1}) // Call the custom component.
713      Line()
714        .width('100%')
715        .height(10)
716        .backgroundColor('#000000').margin(10)
717      Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2
718        .fontSize(30)
719        .fontWeight(FontWeight.Bold)
720      ChildPage ({childInfo: this.info2}) // Call the custom component.
721      Line()
722        .width('100%')
723        .height(10)
724        .backgroundColor('#000000').margin(10)
725      Button("change info1&info2")
726        .onClick(() => {
727          this.info1 = { name: "Cat", age: 18} // Text1 is not re-rendered because no decorator is used to listen for value changes.
728          this.info2 = { name: "Cat", age: 18} // Text2 is re-rendered because a decorator is used to listen for value changes.
729        })
730    }
731  }
732}
733```
734
735## FAQs
736
737### Two or More Parameters Are Used in the \@Builder
738
739When two or more parameters are used, the value change does not trigger the UI re-rendering even if the parameters are passed in the form of object literals.
740
741[Negative Example]
742
743```ts
744class GlobalTmp {
745  str_value: string = 'Hello';
746}
747
748@Builder function overBuilder(param: GlobalTmp, num: number) {
749  Column() {
750    Text(`str_value: ${param.str_value}`)
751    Text(`num: ${num}`)
752  }
753}
754
755@Entry
756@Component
757struct Parent {
758  @State objParam: GlobalTmp = new GlobalTmp();
759  @State num: number = 0;
760  build() {
761    Column() {
762      Text('Render the UI by calling the @Builder')
763        .fontSize(20)
764      // Two parameters are used, which is incorrect.
765      overBuilder({str_value: this.objParam.str_value}, this.num)
766      Line()
767        .width('100%')
768        .height(10)
769        .backgroundColor('#000000').margin(10)
770      Button('Click to change parameter').onClick(() => {
771        this.objParam.str_value = 'Hello World';
772        this.num = 1;
773      })
774    }
775  }
776}
777```
778
779[Negative Example]
780
781```ts
782class GlobalTmp {
783  str_value: string = 'Hello';
784}
785class SecondTmp {
786  num_value: number = 0;
787}
788@Builder function overBuilder(param: GlobalTmp, num: SecondTmp) {
789  Column() {
790    Text(`str_value: ${param.str_value}`)
791    Text(`num: ${num.num_value}`)
792  }
793}
794
795@Entry
796@Component
797struct Parent {
798  @State strParam: GlobalTmp = new GlobalTmp();
799  @State numParam: SecondTmp = new SecondTmp();
800  build() {
801    Column() {
802      Text('Render the UI by calling the @Builder')
803        .fontSize(20)
804      // Two parameters are used, which is incorrect.
805      overBuilder({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value})
806      Line()
807        .width('100%')
808        .height(10)
809        .backgroundColor('#000000').margin(10)
810      Button('Click to change parameter').onClick(() => {
811        this.strParam.str_value = 'Hello World';
812        this.numParam.num_value = 1;
813      })
814    }
815  }
816}
817```
818
819Only one parameter can be used in the \@Builder. When one parameter is passed in the form of object literals, the value change triggers the UI re-rendering.
820
821[Positive Example]
822
823```ts
824class GlobalTmp {
825  str_value: string = 'Hello';
826  num_value: number = 0;
827}
828@Builder function overBuilder(param: GlobalTmp) {
829  Column() {
830    Text(`str_value: ${param.str_value}`)
831    Text(`num: ${param.num_value}`)
832  }
833}
834
835@Entry
836@Component
837struct Parent {
838  @State objParam: GlobalTmp = new GlobalTmp();
839  build() {
840    Column() {
841      Text('Render the UI by calling the @Builder')
842        .fontSize(20)
843      overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value})
844      Line()
845        .width('100%')
846        .height(10)
847        .backgroundColor('#000000').margin(10)
848      Button('Click to change parameter').onClick(() => {
849        this.objParam.str_value = 'Hello World';
850        this.objParam.num_value = 1;
851      })
852    }
853  }
854}
855```
856
857### Component Used in the \@Builder Function Is Not Added to a Root Node
858
859When using the **if** statement in the \@Builder function, if the created component is not added to the **Column** or **Row** root node, the component cannot be created.
860
861[Negative Example]
862
863```ts
864const showComponent: boolean = true;
865@Builder function OverlayNode() {
866  // The Text component is not created without adding it to the Column or Row root node.
867  if (showComponent) {
868      Text("This is overlayNode Blue page")
869        .fontSize(20)
870        .fontColor(Color.Blue)
871        .height(100)
872        .textAlign(TextAlign.End)
873    } else {
874      Text("This is overlayNode Red page")
875        .fontSize(20)
876        .fontColor(Color.Red)
877    }
878}
879
880@Entry
881@Component
882struct OverlayExample {
883
884  build() {
885    RelativeContainer() {
886      Text('Hello World')
887        .overlay(OverlayNode(), { align: Alignment.Center})
888    }
889    .height('100%')
890    .width('100%')
891  }
892}
893```
894
895[Positive Example]
896
897```ts
898const showComponent: boolean = true;
899@Builder function OverlayNode() {
900  Column() {
901    if (showComponent) {
902      Text("This is overlayNode Blue page")
903        .fontSize(20)
904        .fontColor(Color.Blue)
905        .height(100)
906        .textAlign(TextAlign.End)
907    } else {
908      Text("This is overlayNode Red page")
909        .fontSize(20)
910        .fontColor(Color.Red)
911    }
912  }
913}
914
915@Entry
916@Component
917struct OverlayExample {
918
919  build() {
920    RelativeContainer() {
921      Text('Hello World')
922        .overlay(OverlayNode(), { align: Alignment.Center})
923    }
924    .height('100%')
925    .width('100%')
926  }
927}
928```
929