1# Setting Theme Skinning 2 3## Overview 4 5Applications developed using the ArkTS-based declarative development paradigm can implement component theming, including local light/dark modes and dynamic skin changes. This feature does not support the C-API and Node-API, and it does not support theme settings for abilities and windows. 6This document covers the following topics: 7- [Customizing Brand Colors](#customizing-brand-colors) 8- [Setting Custom Brand Colors for Application Components](#setting-custom-brand-colors-for-application-components) 9- [Setting a Custom Theme Style for Specific Application Pages](#setting-a-custom-theme-style-for-specific-application-pages) 10- [Setting Local Light and Dark Modes for Application Pages](#setting-local-light-and-dark-modes-for-application-pages) 11 12 13## Customizing Brand Colors 14Use [CustomTheme](../reference/apis-arkui/js-apis-arkui-theme.md#customtheme) to tailor themes, by selectively overriding the properties you wish to modify; the unmodified properties will inherit from the system default settings, as described in [System Default Token Color Values](#system-default-token-color-values). The following is an example. 15 16 ```ts 17 import { CustomColors, CustomTheme } from '@kit.ArkUI' 18 19 export class AppColors implements CustomColors { 20 // Custom brand color 21 brand: ResourceColor = '#FF75D9'; 22 } 23 24 export class AppTheme implements CustomTheme { 25 public colors: AppColors = new AppColors() 26 } 27 28 export let gAppTheme: CustomTheme = new AppTheme() 29 ``` 30 31## Setting Custom Brand Colors for Application Components 32- Set the custom brand colors at the page entry point by executing [ThemeControl](../reference/apis-arkui/js-apis-arkui-theme.md#themecontrol) before the page builds. 33Use the [onWillApplyTheme](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onwillapplytheme12) callback function to allow custom components to access the currently active **Theme** object. 34 35 ```ts 36 import { Theme, ThemeControl } from '@kit.ArkUI' 37 import { gAppTheme } from './AppTheme' 38 39 // Execute ThemeControl before the page builds. 40 ThemeControl.setDefaultTheme(gAppTheme) 41 42 @Entry 43 @Component 44 struct DisplayPage { 45 @State menuItemColor: ResourceColor = $r('sys.color.background_primary') 46 47 onWillApplyTheme(theme: Theme) { 48 this.menuItemColor = theme.colors.backgroundPrimary; 49 } 50 51 build() { 52 Column() { 53 List({ space: 10 }) { 54 ListItem() { 55 Column({ space: '5vp' }) { 56 Text('Color mode') 57 .margin({ top: '5vp', left: '14fp' }) 58 .width('100%') 59 Row() { 60 Column() { 61 Text('Light') 62 .fontSize('16fp') 63 .textAlign(TextAlign.Start) 64 .alignSelf(ItemAlign.Center) 65 Radio({ group: 'light or dark', value: 'light' }) 66 .checked(true) 67 } 68 .width('50%') 69 70 Column() { 71 Text('Dark') 72 .fontSize('16fp') 73 .textAlign(TextAlign.Start) 74 .alignSelf(ItemAlign.Center) 75 Radio({ group: 'light or dark', value: 'dark' }) 76 } 77 .width('50%') 78 } 79 } 80 .width('100%') 81 .height('90vp') 82 .borderRadius('10vp') 83 .backgroundColor(this.menuItemColor) 84 } 85 86 ListItem() { 87 Column() { 88 Text('Brightness') 89 .width('100%') 90 .margin({ top: '5vp', left: '14fp' }) 91 Slider({ value: 40, max: 100 }) 92 } 93 .width('100%') 94 .height('70vp') 95 .borderRadius('10vp') 96 .backgroundColor(this.menuItemColor) 97 } 98 99 ListItem() { 100 Column() { 101 Row() { 102 Column({ space: '5vp' }) { 103 Text('Touch sensitivity') 104 .fontSize('16fp') 105 .textAlign(TextAlign.Start) 106 .width('100%') 107 Text('Increase the touch sensitivity of your screen' + 108 ' for use with screen protectors') 109 .fontSize('12fp') 110 .fontColor(Color.Blue) 111 .textAlign(TextAlign.Start) 112 .width('100%') 113 } 114 .alignSelf(ItemAlign.Center) 115 .margin({ left: '14fp' }) 116 .width('75%') 117 118 Toggle({ type: ToggleType.Switch, isOn: true }) 119 .margin({ right: '14fp' }) 120 .alignSelf(ItemAlign.Center) 121 } 122 .width('100%') 123 .height('80vp') 124 } 125 .width('100%') 126 .borderRadius('10vp') 127 .backgroundColor(this.menuItemColor) 128 } 129 } 130 } 131 .padding('10vp') 132 .backgroundColor('#dcdcdc') 133 .width('100%') 134 .height('100%') 135 } 136 } 137 ``` 138 139- Within an ability, set [ThemeControl](../reference/apis-arkui/js-apis-arkui-theme.md#themecontrol) by calling [setDefaultTheme](../reference/apis-arkui/js-apis-arkui-theme.md#setdefaulttheme) in the **onWindowStageCreate()** API. 140 141 ```ts 142 import {AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 143 import { hilog } from '@kit.PerformanceAnalysisKit'; 144 import { window, CustomColors, ThemeControl } from '@kit.ArkUI'; 145 146 class AppColors implements CustomColors { 147 fontPrimary = 0xFFD53032 148 iconOnPrimary = 0xFFD53032 149 iconFourth = 0xFFD53032 150 } 151 152 const abilityThemeColors = new AppColors(); 153 154 export default class EntryAbility extends UIAbility { 155 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 156 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 157 } 158 159 onDestroy() { 160 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 161 } 162 163 onWindowStageCreate(windowStage: window.WindowStage) { 164 // Main window is created, set main page for this ability 165 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 166 167 windowStage.loadContent('pages/Index', (err, data) => { 168 if (err.code) { 169 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 170 return; 171 } 172 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 173 // Call setDefaultTheme in the onWindowStageCreate() API. 174 ThemeControl.setDefaultTheme({ colors: abilityThemeColors }) 175 hilog.info(0x0000, 'testTag', '%{public}s', 'ThemeControl.setDefaultTheme done'); 176 }); 177 } 178 179 } 180 ``` 181 182 183 184Note: If the parameter for **setDefaultTheme** is undefined, refer to [System Default Token Color Values](#system-default-token-color-values) for the default color values associated with the tokens. 185 186## Setting a Custom Theme Style for Specific Application Pages 187Use [WithTheme](../reference/apis-arkui/arkui-ts/ts-container-with-theme.md) to apply the color scheme of a custom theme to the default styles of components within the scope. This way, the colors of components within the **WithTheme** scope align with the theme's color scheme. 188In the example below, components within the scope are styled with a custom theme by using **WithTheme({ theme: this.myTheme })**. You can switch to a different theme style by updating **this.myTheme**. 189The [onWillApplyTheme](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onwillapplytheme12) callback function allows custom components to access the currently active **Theme** object. 190 191 ```ts 192 import { CustomColors, CustomTheme, Theme } from '@kit.ArkUI' 193 194 class AppColors implements CustomColors { 195 fontPrimary: ResourceColor = $r('app.color.brand_purple') 196 backgroundEmphasize: ResourceColor = $r('app.color.brand_purple') 197 } 198 199 class AppColorsSec implements CustomColors { 200 fontPrimary: ResourceColor = $r('app.color.brand') 201 backgroundEmphasize: ResourceColor = $r('app.color.brand') 202 } 203 204 class AppTheme implements CustomTheme { 205 public colors: AppColors = new AppColors() 206 } 207 208 class AppThemeSec implements CustomTheme { 209 public colors: AppColors = new AppColorsSec() 210 } 211 212 @Entry 213 @Component 214 struct DisplayPage { 215 @State customTheme: CustomTheme = new AppTheme() 216 @State message: string = 'Set a custom theme style for specific pages' 217 count = 0; 218 219 build() { 220 WithTheme({ theme: this.customTheme }) { 221 Row(){ 222 Column() { 223 Text('WithTheme') 224 .fontSize(30) 225 .margin({bottom: 10}) 226 Text(this.message) 227 .margin({bottom: 10}) 228 Button('Change Theme').onClick(() => { 229 this.count++; 230 if (this.count > 1) { 231 this.count = 0; 232 } 233 switch (this.count) { 234 case 0: 235 this.customTheme = new AppTheme(); 236 break; 237 case 1: 238 this.customTheme = new AppThemeSec(); 239 break; 240 } 241 }) 242 } 243 .width('100%') 244 } 245 .height('100%') 246 .width('100%') 247 } 248 } 249 } 250 ``` 251 252 253 254## Setting Local Light and Dark Modes for Application Pages 255Use [WithTheme](../reference/apis-arkui/arkui-ts/ts-container-with-theme.md) to set light and dark modes. [ThemeColorMode](../reference/apis-arkui/arkui-ts/ts-appendix-enums.md#themecolormode10) offers three options: **ThemeColorMode.SYSTEM** for following the system setting, **ThemeColorMode.LIGHT** for light mode, and **ThemeColorMode.DARK** for dark mode.<br> 256Within the **WithTheme** scope, component styles adapt to the specified light or dark color mode by accessing the corresponding system and application resource values, and the color schemes of components are activated according to the chosen color mode.<br> 257In the example below, components within the scope are set to dark mode using **WithTheme({ colorMode: ThemeColorMode.DARK })**. 258 259To enable light and dark modes, add a **dark.json** resource file for the modes to take effect. 260 261 262 263Example of the **dark.json** file content: 264 ```ts 265 { 266 "color": [ 267 { 268 "name": "start_window_background", 269 "value": "#FFFFFF" 270 } 271 ] 272 } 273 ``` 274 275 ```ts 276 @Entry 277 @Component 278 struct DisplayPage { 279 @State message: string = 'Hello World'; 280 @State colorMode: ThemeColorMode = ThemeColorMode.DARK; 281 282 build() { 283 WithTheme({ colorMode: this.colorMode }) { 284 Row() { 285 Column() { 286 Text(this.message) 287 .fontSize(50) 288 .fontWeight(FontWeight.Bold) 289 Button('Switch ColorMode').onClick(() => { 290 if (this.colorMode === ThemeColorMode.LIGHT) { 291 this.colorMode = ThemeColorMode.DARK; 292 } else if (this.colorMode === ThemeColorMode.DARK) { 293 this.colorMode = ThemeColorMode.LIGHT; 294 } 295 }) 296 } 297 .width('100%') 298 } 299 .backgroundColor($r('sys.color.background_primary')) 300 .height('100%') 301 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.END, SafeAreaEdge.BOTTOM, SafeAreaEdge.START]) 302 } 303 } 304 } 305 ``` 306 307 308 309## System Default Token Color Values 310 311| Token | Category| Light | | Dark | | 312|--------------------------------------------|-----| --- |-----------| ------- | -------------------------------------------- | 313| theme.colors.brand | Brand color.|#ff0a59f7|  |#ff317af7|| 314| theme.colors.warning | Alert color.|#ffe84026|  |#ffd94838|| 315| theme.colors.alert | Warning color.|#ffed6f21|  |#ffdb6b42|| 316| theme.colors.confirm | Confirmation color.|#ff64bb5c|  |#ff5ba854|| 317| theme.colors.fontPrimary | Primary text color.| #e5000000 |  |#e5ffffff|| 318| theme.colors.fontSecondary | Secondary text color.| #99000000 |  |#99ffffff|| 319| theme.colors.fontTertiary | Tertiary text color.| #66000000 |  |#66ffffff|| 320| theme.colors.fontFourth | Quaternary text color.| #33000000 |  |#33ffffff|| 321| theme.colors.fontEmphasize | Highlight text color.| #ff0a59f7 |  |#ff317af7|| 322| theme.colors.fontOnPrimary | Primary text invert color.| #ffffffff |  |#ff000000|| 323| theme.colors.fontOnSecondary | Secondary text invert color.| #99ffffff |  |#99000000|| 324| theme.colors.fontOnTertiary | Tertiary text invert color.| #66ffffff |  |#66000000|| 325| theme.colors.fontOnFourth | Quaternary text invert color.| #33ffffff |  |#33000000|| 326| theme.colors.iconPrimary | Primary icon color.| #e5000000 |  |#e5ffffff|| 327| theme.colors.iconSecondary | Secondary icon color.| #99000000 |  |#99ffffff|| 328| theme.colors.iconTertiary | Tertiary icon color.| #66000000 |  |#66ffffff|| 329| theme.colors.iconFourth | Quaternary icon color.| #33000000 |  |#33ffffff|| 330| theme.colors.iconEmphasize | Emphasis icon color.| #ff0a59f7 |  |#ff317af7|| 331| theme.colors.iconSubEmphasize | Emphasis auxiliary icon color.| #660a59f7 |  |#66317af7|| 332| theme.colors.iconOnPrimary | Primary icon invert color.| #ffffffff |  |#ff000000|| 333| theme.colors.iconOnSecondary | Secondary icon invert color.| #99ffffff |  |#99000000|| 334| theme.colors.iconOnTertiary | Tertiary icon invert color.| #66ffffff |  |#66000000|| 335| theme.colors.iconOnFourth | Quaternary icon invert color.| #33ffffff |  |#33000000|| 336| theme.colors.backgroundPrimary | Primary background color (solid, opaque).| #ffffffff |  |#ffe5e5e5|| 337| theme.colors.backgroundSecondary | Secondary background color (solid, opaque).| #fff1f3f5 |  |#ff191a1c|| 338| theme.colors.backgroundTertiary | Tertiary background color (solid, opaque).| #ffe5e5ea |  |#ff202224|| 339| theme.colors.backgroundFourth | Quaternary background color (solid, opaque).| #ffd1d1d6 |  |#ff2e3033|| 340| theme.colors.backgroundEmphasize | Emphasis background color (solid, opaque).| #ff0a59f7 |  |#ff317af7|| 341| theme.colors.compForegroundPrimary | Foreground.| #ff000000 |  | #ffe5e5e5 || 342| theme.colors.compBackgroundPrimary | White background.| #ffffffff || #ffffffff || 343| theme.colors.compBackgroundPrimaryTran | White transparent background.| #ffffffff || #33ffffff || 344| theme.colors.compBackgroundPrimaryContrary | Always-on background.| #ffffffff || #ffe5e5e5 || 345| theme.colors.compBackgroundGray | Gray background.| #fff1f3f5 || #ffe5e5ea || 346| theme.colors.compBackgroundSecondary | Secondary background.| #19000000 || #19ffffff || 347| theme.colors.compBackgroundTertiary | Tertiary background.| #0c000000 || #0cffffff || 348| theme.colors.compBackgroundEmphasize | Emphasis background.| #ff0a59f7 || #ff317af7 || 349| theme.colors.compBackgroundNeutral | Black, neutral, emphasis background.| #ff000000 || #ffffffff || 350| theme.colors.compEmphasizeSecondary | 20% emphasis background.| #330a59f7 || #33317af7 || 351| theme.colors.compEmphasizeTertiary | 10% emphasis background.| #190a59f7 || #19317af7 || 352| theme.colors.compDivider | Divider color.| #33000000 || #33ffffff || 353| theme.colors.compCommonContrary | Common invert color.| #ffffffff || #ff000000 || 354| theme.colors.compBackgroundFocus | Background color in the focused state.| #fff1f3f5 || #ff000000 || 355| theme.colors.compFocusedPrimary | Primary inverted color in the focused state.| #e5000000 || #e5ffffff || 356| theme.colors.compFocusedSecondary | Secondary inverted color in the focused state.| #99000000 || #99ffffff || 357| theme.colors.compFocusedTertiary | Tertiary inverted color in the focused state.| #66000000 || #66ffffff || 358| theme.colors.interactiveHover | Common interactive color for the hover state.| #0c000000 || #0cffffff || 359| theme.colors.interactivePressed | Common interactive color for the pressed state.| #19000000 || #19ffffff || 360| theme.colors.interactiveFocus | Common interactive color for the focused state.| #ff0a59f7 || #ff317af7 || 361| theme.colors.interactiveActive | Common interactive color for the active state.| #ff0a59f7 || #ff317af7 || 362| theme.colors.interactiveSelect | Common interactive color for the selected state.| #33000000 || #33ffffff || 363| theme.colors.interactiveClick | Common interactive color for the clicked state.| #19000000 || #19ffffff || 364