• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Creating a Custom Component
2
3
4In ArkUI, components are what's displayed on the UI. They can be classified as built-in components – those directly provided by the ArkUI framework, and custom components – those defined by developers. Defining the entire application UI with just built-in components would lead to a monolithic design, low code maintainability, and poor execution performance. A good UI is the result of a well-thought-out development process, with such factors as code reusability, separation of service logic from the UI, and version evolution carefully considered. Creating custom components that encapsulate the UI and some business logic is a critical step in this process.
5
6
7The custom component has the following features:
8
9
10- Combinable: allows you to combine built-in components and other components, as well as their attributes and methods.
11
12- Reusable: can be reused by other components and used as different instances in different parent components or containers.
13
14- Data-driven update: holds some state and triggers UI re-rendering with the change of state variables.
15
16
17The following example shows the basic usage of a custom component.
18
19
20
21```ts
22@Component
23struct HelloComponent {
24  @State message: string = 'Hello, World!';
25
26  build() {
27    // The HelloComponent custom component combines the <Row> and <Text> built-in components.
28    Row() {
29      Text(this.message)
30        .onClick(() => {
31          // The change of the state variable message drives the UI to be re-rendered. As a result, the text changes from "Hello, World!" to "Hello, ArkUI!".
32          this.message = 'Hello, ArkUI!';
33        })
34    }
35  }
36}
37```
38
39
40Multiple **HelloComponent** instances can be created in the **build()** function of other custom components. In this way, **HelloComponent** is reused by those custom components.
41
42
43
44```ts
45@Entry
46@Component
47struct ParentComponent {
48  build() {
49    Column() {
50      Text('ArkUI message')
51      HelloComponent({ message: 'Hello, World!' });
52      Divider()
53      HelloComponent ({ message: 'Hello!' });
54    }
55  }
56}
57```
58
59
60To fully understand the preceding example, a knowledge of the following concepts is essential:
61
62
63- [Basic Structure of a Custom Component](#basic-structure-of-a-custom-component)
64
65- Member functions/Variables
66
67- [Rules of for Custom Component Parameters](#rules-of-for-custom-component-parameters)
68
69- [build Function](#build-function)
70
71- [Universal Style of a Custom Component](#universal-style-of-a-custom-component)
72
73
74
75## Basic Structure of a Custom Component
76
77- struct: The definition of a custom component must start with the \@Component struct followed by the component name, and then component body enclosed by curly brackets {....}. No inheritance is allowed. You can omit the **new** operator when instantiating a struct.
78  > **NOTE**
79  >
80  > The name or its class or function name of a custom component must be different from that of any built-in components.
81
82- \@Component: The \@Component decorator can decorate only the structs declared by the **struct** keyword. After being decorated by \@Component, a struct has the componentization capability. It must implement the **build** function to describe the UI. One struct can be decorated by only one \@Component.
83  > **NOTE**
84  >
85  > Since API version 9, this decorator is supported in ArkTS widgets.
86
87  ```ts
88  @Component
89  struct MyComponent {
90  }
91  ```
92
93- build(): The **build()** function is used to define the declarative UI description of a custom component. Every custom component must define a **build()** function.
94
95  ```ts
96  @Component
97  struct MyComponent {
98    build() {
99    }
100  }
101  ```
102
103- \@Entry: A custom component decorated with \@Entry is used as the default entry component of the page. At most one component can be decorated with \@Entry in a single source file. The \@Entry decorator accepts an optional parameter of type [LocalStorage](arkts-localstorage.md).
104
105  > **NOTE**
106  >
107  > Since API version 9, this decorator is supported in ArkTS widgets.
108
109  ```ts
110  @Entry
111  @Component
112  struct MyComponent {
113  }
114  ```
115
116
117## Member Functions/Variables
118
119In addition to the mandatory **build()** function, a custom component may implement other member functions with the following restrictions:
120
121
122- Static functions are not supported.
123
124- Access to the member functions is always private.
125
126
127A custom component can also implement member variables with the following restrictions:
128
129
130- Static member variables are not supported.
131
132- Access to the member variables is always private. The access rules of member variables are the same as those of member functions.
133
134- Local initialization is optional for some member variables and mandatory for others. For details about whether local initialization or initialization from the parent component is required, see [State Management](arkts-state-management-overview.md).
135
136
137## Rules of for Custom Component Parameters
138
139As can be learnt from preceding examples, a custom component can be created from a **build** or [@Builder](arkts-builder.md) function, and during the creation, parameters can be supplied to the component.
140
141
142```ts
143@Component
144struct MyComponent {
145  private countDownFrom: number = 0;
146  private color: Color = Color.Blue;
147
148  build() {
149  }
150}
151
152@Entry
153@Component
154struct ParentComponent {
155  private someColor: Color = Color.Pink;
156
157  build() {
158    Column() {
159      // Create an instance of MyComponent and initialize its countDownFrom variable with the value 10 and its color variable with the value this.someColor.
160      MyComponent({ countDownFrom: 10, color: this.someColor })
161    }
162  }
163}
164```
165
166
167## build Function
168
169All languages declared in the **build** function are called UI description languages. The UI description languages must comply with the following rules:
170
171- For an \@Entry decorated custom component, exactly one root component is required under the **build** function. This root component must be a container component. **ForEach** is not allowed at the top level.
172  For an \@Component decorated custom component, exactly one root component is required under the **build** function. This root component is not necessarily a container component. **ForEach** is not allowed at the top level.
173
174  ```ts
175  @Entry
176  @Component
177  struct MyComponent {
178    build() {
179      // Exactly one root component is required, and it must be a container component.
180      Row() {
181        ChildComponent()
182      }
183    }
184  }
185
186  @Component
187  struct ChildComponent {
188    build() {
189      // Exactly one root component is required, and it is not necessarily a container component.
190      Image('test.jpg')
191    }
192  }
193  ```
194
195- Local variable declaration is not allowed. The following example is invalid:
196
197  ```ts
198  build() {
199    // Invalid: Local variable declaration is not allowed.
200    let a: number = 1;
201  }
202  ```
203
204- **console.info** cannot be directly used in the UI description, but can be used in methods or functions. The following is an example:
205
206  ```ts
207  build() {
208    // Invalid: Use of console.info is not allowed.
209    console.info('print debug log');
210  }
211  ```
212
213- Creation of a local scope is not allowed. The following example is invalid:
214
215  ```ts
216  build() {
217    // Invalid: Creation of local scope is not allowed.
218    {
219      ...
220    }
221  }
222  ```
223
224- Calling a function other than the \@Builder decorated is not allowed. The parameters of built-in components can be the return values of TS methods.
225
226  ```ts
227  @Component
228  struct ParentComponent {
229    doSomeCalculations() {
230    }
231
232    calcTextValue(): string {
233      return 'Hello World';
234    }
235
236    @Builder doSomeRender() {
237      Text(`Hello World`)
238    }
239
240    build() {
241      Column() {
242        // Invalid: No function calls except @Builder functions.
243        this.doSomeCalculations();
244        // Valid: The function can be called.
245        this.doSomeRender();
246        // Valid: The parameter can be the return value of a TS method.
247        Text(this.calcTextValue())
248      }
249    }
250  }
251  ```
252
253- The **switch** syntax is not allowed. Use **if** instead. The following example is invalid:
254
255  ```ts
256  build() {
257    Column() {
258      // Invalid: The switch syntax is not allowed.
259      switch (expression) {
260        case 1:
261          Text('...')
262          break;
263        case 2:
264          Image('...')
265          break;
266        default:
267          Text('...')
268          break;
269      }
270    }
271  }
272  ```
273
274- Expressions are not allowed. The following example is invalid:
275
276  ```ts
277  build() {
278    Column() {
279      // Invalid: Expressions are not allowed.
280      (this.aVar > 10) ? Text('...') : Image('...')
281    }
282  }
283  ```
284
285
286## Universal Style of a Custom Component
287
288The universal style of a custom component is configured by invoking chainable attribute methods.
289
290
291```ts
292@Component
293struct MyComponent2 {
294  build() {
295    Button(`Hello World`)
296  }
297}
298
299@Entry
300@Component
301struct MyComponent {
302  build() {
303    Row() {
304      MyComponent2()
305        .width(200)
306        .height(300)
307        .backgroundColor(Color.Red)
308    }
309  }
310}
311```
312
313> **NOTE**
314>
315> When ArkUI sets styles for custom components, an invisible container component is set for **MyComponent2**. These styles are set on the container component instead of the **\<Button>** component of **MyComponent2**. As seen from the rendering result, the red background color is not directly applied to the button. Instead, it is applied to the container component that is invisible to users where the button is located.
316