1# Attribute Modifier
2
3With the attribute modifier, you can dynamically set component attributes, complete with the **if/else** syntax and polymorphic style.
4
5>  **NOTE**
6>
7>  This feature is supported since API version 11. Updates will be marked with a superscript to indicate their earliest API version.
8>
9> Ensure that the attributes set in **attributeModifier** are different from those set in other methods. Otherwise, **attributeModifier** does not take effect when the page is refreshed.
10>
11> **attributeModifier** does not support custom components.
12
13## attributeModifier
14
15attributeModifier(modifier: AttributeModifier\<T>)
16
17Creates an attribute modifier.
18
19**Atomic service API**: This API can be used in atomic services since API version 12.
20
21**System capability**: SystemCapability.ArkUI.ArkUI.Full
22
23**Parameters**
24
25| Name  | Type                 | Mandatory| Description                                                        |
26| -------- | --------------------- | ---- | ------------------------------------------------------------ |
27| modifier | [AttributeModifier\<T>](#attributemodifiert) | Yes  | Modifier for dynamically setting attributes on the current component. The **if/else** syntax is supported.<br>**modifier**: attribute modifier. You need a custom class to implement the **AttributeModifier** API.|
28
29## AttributeModifier\<T>
30
31You need a custom class to implement the **AttributeModifier** API.
32
33**Atomic service API**: This API can be used in atomic services since API version 12.
34
35### applyNormalAttribute
36applyNormalAttribute(instance: T) : void
37
38Applies the style of a component in the normal state.
39
40**Atomic service API**: This API can be used in atomic services since API version 12.
41
42### applyPressedAttribute
43applyPressedAttribute(instance: T) : void
44
45Applies the style of a component in the pressed state.
46
47**Atomic service API**: This API can be used in atomic services since API version 12.
48
49### applyFocusedAttribute
50applyFocusedAttribute(instance: T) : void
51
52Applies the style of a component in the focused state.
53
54**Atomic service API**: This API can be used in atomic services since API version 12.
55
56### applyDisabledAttribute
57applyDisabledAttribute(instance: T) : void
58
59Applies the style of a component in the disabled state.
60
61**Atomic service API**: This API can be used in atomic services since API version 12.
62
63### applySelectedAttribute
64applySelectedAttribute(instance: T) : void
65
66Applies the style of a component in the selected state.
67
68In the preceding APIs, **instance** indicates the component type. You can customize these APIs and use them with the **if/else **syntax.
69
70**Atomic service API**: This API can be used in atomic services since API version 12.
71
72**Parameters**
73
74| Name            | Description                                                        |
75| -------------------- | ------------------------------------------------------------ |
76| instance |Component attribute class, which identifies the type of component to which attributes will be applied, for example, **ButtonAttribute** for the **Button** component and **TextAttribute** for the **Text** component.|
77
78**Value range of the instance parameter**
79
80AlphabetIndexerAttribute, BadgeAttribute, BlankAttribute, ButtonAttribute, CalendarPickerAttribute, CanvasAttribute, CheckboxAttribute, CheckboxGroupAttribute, CircleAttribute, ColumnAttribute, ColumnSplitAttribute, ShapeAttribute, CommonAttribute, CounterAttribute, DataPanelAttribute, DatePickerAttribute, DividerAttribute, EllipseAttribute, FlexAttribute, FlowItemAttribute, FormLinkAttribute, GaugeAttribute, GridAttribute, GridColAttribute, ColumnAttribute, GridItemAttribute, GridRowAttribute, HyperlinkAttribute, ImageAttribute, ImageAnimatorAttribute, ImageSpanAttribute, LineAttribute, ListAttribute, ListItemAttribute, ListItemGroupAttribute, LoadingProgressAttribute, MarqueeAttribute, MenuAttribute, MenuItemAttribute, MenuItemGroupAttribute, NavDestinationAttribute, NavigationAttribute, NavigatorAttribute, NavRouterAttribute, PanelAttribute, PathAttribute, PatternLockAttribute, PolygonAttribute, PolylineAttribute, ProgressAttribute, QRCodeAttribute, RadioAttribute, RatingAttribute, RectAttribute, RefreshAttribute, RelativeContainerAttribute, RichEditorAttribute, RichTextAttribute, RowAttribute, RowSplitAttribute, ScrollAttribute, ScrollBarAttribute, SearchAttribute, SelectAttribute, ShapeAttribute, SideBarContainerAttribute, SliderAttribute, SpanAttribute, StackAttribute, StepperAttribute, StepperItemAttribute, SwiperAttribute, SymbolGlyphAttribute, TabContentAttribute, TabsAttribute, TextAttribute, TextAreaAttribute, TextClockAttribute, TextInputAttribute, TextPickerAttribute, TextTimerAttribute, TimePickerAttribute, ToggleAttribute, VideoAttribute, WaterFlowAttribute, XComponentAttribute, ParticleAttribute<!--Del-->, EffectComponentAttribute, FormComponentAttribute, PluginComponentAttribute, RemoteWindowAttribute, UIExtensionComponentAttribute<!--DelEnd-->
81
82**Supported attributes**
83
84Attributes whose input parameters are [CustomBuilder](ts-types.md#custombuilder8) or lamda expressions are not supported. In addition, gestures are not supported. Only the following events are supported: **onClick**, **onTouch**, **onAppear**, **onDisAppear**, **onMouse**, **onHover**, **onKeyEvent**, **onBlur**, **onFocus**, **onAreaChange**, **onSizeChange**, **onGestureJudgeBegin**, **onGestureRecognizerJudgeBegin**, and **shouldBuiltInRecognizerParallelWith**. Deprecated attributes are not supported. When an attribute not supported is used, the exception "Method not implemented " is thrown.
85## Custom Modifier
86Custom modifiers can be used in building components and configuring attributes since API version 12. Through the custom modifiers, you can call the attribute and style APIs of encapsulated components.
87
88**Supported custom modifiers**
89
90CommonModifier, ColumnModifier, ColumnSplitModifier, RowModifier, RowSplitModifier, SideBarContainerModifier, BlankModifier, DividerModifier, GridColModifier, GridRowModifier, NavDestinationModifier, NavigatorModifier, StackModifier, NavigationModifier, NavRouterModifier, StepperItemModifier, TabsModifier, GridModifier, GridItemModifier, ListModifier, ListItemModifier, ListItemGroupModifier, ScrollModifier, SwiperModifier, WaterFlowModifier, ButtonModifier, CounterModifier, TextPickerModifier, TimePickerModifier, ToggleModifier, CalendarPickerModifier, CheckboxModifier, CheckboxGroupModifier, DatePickerModifier, RadioModifier, RatingModifier, SelectModifier, SliderModifier, PatternLockModifier, SpanModifier, RichEditorModifier, RefreshModifier, SearchModifier, TextAreaModifier, TextModifier, TextInputModifier, ImageSpanModifier, ImageAnimatorModifier, ImageModifier, VideoModifier, DataPanelModifier, GaugeModifier, LoadingProgressModifier, MarqueeModifier, ProgressModifier, QRCodeModifier, TextClockModifier, TextTimerModifier, LineModifier, PathModifier, PolygonModifier, PolylineModifier, RectModifier, ShapeModifier, AlphabetIndexerModifier, FormComponentModifier, HyperlinkModifier, MenuModifier, MenuItemModifier, PanelModifier, SymbolGlyphModifier, ParticleModifier
91**CommonModifier** can be used for unexposed components.
92
93**Precautions**
941. When a custom modifier is applied to a component, the corresponding attribute of the component takes effect.
952. Updating the attribute value of a custom modifier changes the corresponding attribute of the component to which the modifier is applied. The custom modifier is a base class, and the constructed object is a child class object. When using the object, use **as** to assert the type as a child class.
963. With a custom modifier applied to two components, updating the attribute value of the custom modifier changes the corresponding attributes of both components.
974. If attributes A and B are set through a custom modifier, and then attributes C and D are set through other means, all the four attributes take effect on the component.
985. The custom modifier does not support change observation for @State decorated variables. For details, see Example 2.
996. If you use **attributeModifier** to set attributes multiple times, all the set attributes take effect, and those attributes that are set multiple times take effect based on the configuration sequence.
100
101## Example
102### Example 1
103
104For details about how to use the attribute modifier with state management V2, see [Modifier and makeObserved](../../../quick-start/arkts-v1-v2-migration.md#modifier).
105
106```ts
107// xxx.ets
108class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
109  isDark: boolean = false
110  applyNormalAttribute(instance: ButtonAttribute): void {
111    if (this.isDark) {
112      instance.backgroundColor(Color.Black)
113    } else {
114      instance.backgroundColor(Color.Red)
115    }
116  }
117}
118
119@Entry
120@Component
121struct attributeDemo {
122  @State modifier: MyButtonModifier = new MyButtonModifier()
123
124  build() {
125    Row() {
126      Column() {
127        Button("Button")
128          .attributeModifier(this.modifier)
129          .onClick(() => {
130            this.modifier.isDark = !this.modifier.isDark
131          })
132      }
133      .width('100%')
134    }
135    .height('100%')
136  }
137}
138```
139![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
140
141
142
143```ts
144// xxx.ets
145class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
146  applyNormalAttribute(instance: ButtonAttribute): void {
147    instance.backgroundColor(Color.Black)
148  }
149
150  applyPressedAttribute(instance: ButtonAttribute): void {
151    instance.backgroundColor(Color.Red)
152  }
153}
154
155@Entry
156@Component
157struct attributePressedDemo {
158  @State modifier: MyButtonModifier = new MyButtonModifier()
159
160  build() {
161    Row() {
162      Column() {
163        Button("Button")
164          .attributeModifier(this.modifier)
165      }
166      .width('100%')
167    }
168    .height('100%')
169  }
170}
171```
172![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
173
174### Example 2
175The custom modifier does not support change observation for @State decorated variables.
176```ts
177import { CommonModifier } from "@kit.ArkUI"
178
179class MyModifier extends CommonModifier {
180  applyNormalAttribute(instance: CommonAttribute) : void{
181    super.applyNormalAttribute?.(instance);
182  }
183}
184
185@Component
186struct MyImage1 {
187  @Link modifier : CommonModifier
188
189  build(){
190    Image($r("app.media.testImage")).attributeModifier(this.modifier as MyModifier)
191  }
192}
193@Entry
194@Component
195struct Index {
196  index : number = 0;
197  @State width1 : number = 100;
198  @State height1 : number = 100;
199  @State myModifier: CommonModifier = new MyModifier().width(this.width1).height(this.height1).margin(10)
200
201  build() {
202    Column() {
203      Button($r("app.string.EntryAbility_label"))
204        .margin(10)
205        .onClick(() => {
206          console.log("Modifier","onClick")
207          this.index ++;
208          if(this.index %2 === 1){
209            this.width1 = 10;
210            console.log("Modifier","setGroup1")
211          }else{
212            this.width1 = 10;
213            console.log("Modifier","setGroup2")
214          }
215        })
216      MyImage1({modifier:this.myModifier})
217    }
218    .width('100%')
219  }
220}
221```
222![attributeModifier2](figures/attributeModifier2.gif)
223### Example 3
224In this example, the custom modifier sets the **width** and **height** attributes, and the **borderStyle** and **borderWidth** attributes are set through a button click. In this case, all the four attributes take effect when the button is clicked.
225```ts
226import { CommonModifier } from "@kit.ArkUI"
227
228class MyModifier extends CommonModifier {
229  applyNormalAttribute(instance: CommonAttribute) : void{
230    super.applyNormalAttribute?.(instance);
231  }
232
233  public setGroup1() : void {
234    this.borderStyle(BorderStyle.Dotted)
235    this.borderWidth(8)
236  }
237
238  public setGroup2() : void {
239    this.borderStyle(BorderStyle.Dashed)
240    this.borderWidth(8)
241  }
242}
243
244@Component
245struct MyImage1 {
246  @Link modifier : CommonModifier
247
248  build(){
249    Image($r("app.media.testImage")).attributeModifier(this.modifier as MyModifier)
250  }
251}
252
253@Entry
254@Component
255struct Index {
256  @State myModifier: CommonModifier = new MyModifier().width(100).height(100).margin(10)
257  index : number = 0;
258
259  build() {
260    Column() {
261      Button($r("app.string.EntryAbility_label"))
262        .margin(10)
263        .onClick(() => {
264          console.log("Modifier","onClick")
265          this.index ++;
266          if(this.index %2 === 1){
267            (this.myModifier as MyModifier).setGroup1()
268            console.log("Modifier","setGroup1")
269          }else{
270            (this.myModifier as MyModifier).setGroup2()
271            console.log("Modifier","setGroup2")
272          }
273        })
274      MyImage1({modifier:this.myModifier})
275    }
276    .width('100%')
277  }
278}
279```
280![attributeModifier](figures/attributeModifier.gif)
281<!--no_check-->