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