1# Focus Event 2 3## Basic Concepts and Specifications 4 5### Basic Concepts 6 7**Focus, Focus Chain, and Focus Traversal** 8 9- Focus: refers to the single interactive element on the current application screen. When users interact indirectly with the application using non-pointing input devices such as keyboards, TV remote controls, or in-car joysticks/knobs, navigation and interaction based on focus are crucial means of input. 10- Focus chain: refers to the sequence of nodes from the root to a focused component in the application's component tree, where all nodes are considered focused. 11- Focus traversal: refers to the behavior of focus shifting between components in an application. This process is transparent to the user but can be monitored through **onFocus** and **onBlur** events. For details on how focus traversal is managed, see [Focus Traversal Guidelines](#focus-traversal-guidelines) 12 13 14**Focus State** 15 16Refers to the style indicating the currently focused component. 17 18- Display rules: The focus state is not displayed by default; it only appears when the application is active. A component with the focus state is definitely focused, but not all focused components show the state, depending on the activation status. Most components come with default focus state styles; you customize these styles when needed. Once customized, the component will no longer display the default focus state style. For details about how to set the focus state style, see [Focus Style](#focus-style). In a focus chain, if multiple components have the focus state, the system shows the focus state for only one, prioritizing the child component's focus state over others. 19- Entering the activation state: Pressing the **Tab** key on an external keyboard or using the **activate(true)** API of **FocusController** activates focus, allowing subsequent use of the **Tab** key or arrow keys for focus traversal. The initial **Tab** press that activates focus does not cause focus to move. 20- Exiting the activation state: Focus activation ends when the application receives either the **activate(true)** API call from **FocusController** or any form of click event, such as touchscreen presses or mouse clicks. 21 22 23**Hierarchical Pages** 24 25Hierarchical pages are specialized container components, such as **Page**, **Dialog**, **SheetPage**, **ModalPage**, **Menu**, **Popup**, **NavBar**, and **NavDestination**, within a focus framework. These components typically have the following key features: 26 27- Visual layering: They appear on top of other content, creating a distinct visual hierarchy. 28- Focus capture: They automatically take focus when first displayed. 29- Focus limitation: When focus is within these components, users cannot use keyboard keys to move focus outside to other elements. In other words, focus movement is confined within the component. 30 31An application always has at least one hierarchical page in focus. When this hierarchical page is closed or no longer visible, the focus shifts to another, ensuring smooth user interaction. 32 33> **NOTE** 34> 35> The **Popup** component does not capture focus if it has **focusable** set to **false**. 36> 37> The **NavBar** and **NavDestination** components do not restrict focus movement and share the focus scope of their immediate parent hierarchical page. 38 39**Root Container** 40 41In hierarchical pages, the root container is where the default focus resides when the page is first shown. 42 43You can change the default focus using the **defaultFocus** attribute. 44 45Pressing **Tab** with focus on the root container activates focus and passes it to child components. Focus proceeds to the last focused child or the first child if no previous focus exists, until it reaches the leaf node. 46 47### Focus Traversal Guidelines 48 49Focus traversal can be divided into active and passive based on how it is triggered. 50 51**Active Focus Traversal** 52 53 54Active focus traversal refers to focus movement initiated by deliberate actions, such as keyboard shortcuts (**Tab**, **Shift+Tab**, arrow keys) and programmatic focus control through **requestFocus**, **clearFocus**, and **focusOnTouch**. 55 56 57- Keyboard traversal 581. Prerequisite: The application is in the focus activation state. 592. Scope: limited to the currently focused hierarchical page, as detailed in the "Focus limitation" section under "Hierarchical Pages." 603. Key types: 61**Tab** key: follows a Z-shaped logic to traverse all leaf nodes within the scope, looping back to the first after the last. 62**Shift+Tab**: reverses the direction of the **Tab** key. 63Arrow keys (up, down, left, and right): moves focus in a cross-shaped pattern, with container-specific algorithms determining the next focus in a single-layer container. If the algorithm determines the next focus should be on a container component, the system uses a center-point distance priority algorithm to further identify the target child node within the container. 644. Traversal algorithm: Each focusable container has a unique algorithm defining how focus moves. 655. Priority: Child components take precedence in handling keyboard events over parents. 66 67- requestFocus 68Moves focus to a specific component, which is allowed across hierarchical pages but not across windows or different ArkUI instances. 69For details, see [Active Focus Acquisition/Loss](#active-focus-acquisitionloss). 70 71- clearFocus 72Clears the focus within the current hierarchical page, with the focus reverting to the root container. For details, see [clearFocus](../reference/apis-arkui/js-apis-arkui-UIContext.md#clearfocus12). 73 74- focusOnTouch 75Enables a component to gain focus on touch. It is ineffective on non-focusable components. For container components, focus goes to the last focused child or the first focusable child upon touch. For details, see [focusOnTouch](../reference/apis-arkui/arkui-ts/ts-universal-attributes-focus.md#focusontouch9). 76 77 78**Passive Focus Traversal** 79 80Passive focus traversal occurs when the focus automatically shifts due to system actions or other operations without developer intervention, reflecting the default behavior of the focus system. 81 82 83Mechanisms that trigger passive focus traversal include: 84 85- Component removal: If a focused component is removed, the system tries to shift focus to the next available sibling, following a back-to-front order. If no siblings are focusable, focus is released to the parent component. 86- Attribute change: Changing a component's **focusable** or **enabled** to **false**, or **visibility** to invisible causes the system to automatically move focus to another focusable component, using the same method as for component removal. 87- Hierarchical page transition: During switching between hierarchical pages, the current page's focus is automatically released, and the new page may automatically gain focus according to preset logic. 88- **Web** component initialization: The **Web** component may immediately gain focus upon creation if designed to do so (for example, certain dialog boxes or text boxes), which is part of the component's behavior and not governed by the focus framework specifications. 89 90### Focus Traversal Algorithms 91 92In the focus management system, every focusable container is assigned a specific algorithm that dictates how focus moves from the current to the next focusable child component when **Tab**, **Shift+Tab**, or arrow keys are used. 93 94The algorithm used by a container is based on its UX design and is implemented by the component itself. The focus framework supports three focus traversal algorithms: linear, projection, and custom. 95 96**Linear Focus Traversal Algorithm** 97 98 99The linear focus traversal algorithm is the default algorithm, focusing on the order of child nodes in the node tree, commonly used in single-direction layouts such as **Row**, **Column**, and **Flex** containers. Its operation rules are as follows: 100 101 102- Order dependency: The focus order is based solely on the mounting sequence of child nodes in the node tree, independent of their visual layout. 103- **Tab** key focus traversal: The **Tab** key moves focus through focusable elements in the order they are mounted in the component tree. 104- Arrow key focus traversal: Arrow keys perpendicular to the container's layout direction are ignored. For example, a horizontal **Row** container does not accept focus requests from up and down keys. 105- Boundary handling: The container rejects focus requests in the opposite direction from the current focus edge. For example, if the focus is on the first child of a horizontal **Row** container, it won't process leftward focus requests. 106 107 108**Projection-based Focus Traversal Algorithm** 109 110The projection-based focus traversal algorithm determines the next focus based on the overlap area and center-point distance of the projection of the current focused component in the direction of focus movement. It is particularly suitable for containers with varying child sizes, such as the **Flex** component with the **wrap** attribute. Its operation rules are as follows: 111 112 113- Arrow keys: Focus goes to the child with the largest overlap area and the shortest center-point distance to the projection of the current focus. If multiple children qualify, the first in the node tree is chosen. If no components overlap with the projection, the focus request is unprocessable. 114- **Tab** key: It mimics a rightward shift to find the next focus; if none is available, it simulates moving the current focus down its height, and then checks leftward. The child farthest in the direction with overlapping projection wins. 115- **Shift+Tab** key: It mimics a leftward shift to find the next focus; if none is available, it simulates moving the current focus up its height, and then checks rightward. The child farthest in the direction with overlapping projection wins. 116 117 118**Custom Focus Traversal Algorithm** 119 120The custom focus traversal algorithm is defined by the component itself, allowing for specific focus traversal behaviors as determined by the component's design specifications. 121 122## onFocus/onBlur Events 123 124```ts 125onFocus(event: () => void) 126``` 127 128 129Triggered when the bound component obtains focus. 130 131```ts 132onBlur(event:() => void) 133``` 134 135Triggered when the bound component loses focus. 136 137The **onFocus** and **onBlur** APIs are usually used in pairs to listen for the focus changes of the component. 138 139```ts 140// xxx.ets 141@Entry 142@Component 143struct FocusEventExample { 144 @State oneButtonColor: Color = Color.Gray; 145 @State twoButtonColor: Color = Color.Gray; 146 @State threeButtonColor: Color = Color.Gray; 147 148 build() { 149 Column({ space: 20 }) { 150 // You can use the up and down arrow keys on an external keyboard to move the focus between the three buttons. When a button gains focus, its color changes. When it loses focus, its color changes back. 151 Button('First Button') 152 .width(260) 153 .height(70) 154 .backgroundColor(this.oneButtonColor) 155 .fontColor(Color.Black) 156 // Listen for the focus obtaining event of the first component and change its color when it obtains focus. 157 .onFocus(() => { 158 this.oneButtonColor = Color.Green; 159 }) 160 // Listen for the focus loss event of the first component and change its color when it loses focus. 161 .onBlur(() => { 162 this.oneButtonColor = Color.Gray; 163 }) 164 165 Button('Second Button') 166 .width(260) 167 .height(70) 168 .backgroundColor(this.twoButtonColor) 169 .fontColor(Color.Black) 170 // Listen for the focus obtaining event of the second component and change its color when it obtains focus. 171 .onFocus(() => { 172 this.twoButtonColor = Color.Green; 173 }) 174 // Listen for the focus loss event of the second component and change its color when it loses focus. 175 .onBlur(() => { 176 this.twoButtonColor = Color.Grey; 177 }) 178 179 Button('Third Button') 180 .width(260) 181 .height(70) 182 .backgroundColor(this.threeButtonColor) 183 .fontColor(Color.Black) 184 // Listen for the focus obtaining event of the third component and change its color when it obtains focus. 185 .onFocus(() => { 186 this.threeButtonColor = Color.Green; 187 }) 188 // Listen for the focus loss event of the third component and change its color when it loses focus. 189 .onBlur(() => { 190 this.threeButtonColor = Color.Gray ; 191 }) 192 }.width('100%').margin({ top: 20 }) 193 } 194} 195``` 196 197 198 199 200 201The preceding example includes three steps: 202 203- When the application is opened, pressing the **Tab** key activates focus traversal, **First Button** displays a focus state style – a blue bounding box around the component – and its **onFocus** callback is triggered, changing the background color to green. 204- When the **Tab** key is pressed again, **Second Button** gains focus, triggering its **onFocus** callbacktriggered, and its background color turns green, while **First Button** loses focus, triggering its **onBlur** callback, and its background color reverts to gray. 205- A subsequent **Tab** key press causes **Third Button** to gain focus, triggering its **onFocus** callback, and its background color turns green. Concurrently, **Second Button** loses focus, triggering its **onBlur** callback, and its background color reverts to gray. 206 207## Setting Whether a Component Is Focusable 208 209```ts 210focusable(value: boolean) 211``` 212 213Sets whether the component is focusable. 214 215Components can be classified into the following types based on their focus capability: 216 217- Default focusable components: These components are usually interactive components, such as **Button**, **Checkbox**, and **TextInput**. 218 219- Components with focus capability but not focusable by default: Typical examples are **Text** and **Image**. To enable them to be focusable, set **focusable(true)**. When these components do not have the **focusable** attribute set, setting an **onClick** event or a single-tap gesture implicitly makes them focusable. However, when these components have the **focusable** attribute set to **false**, they are still not focusable even if you bind the aforementioned event or gesture to them. 220 221- Non-focusable components: Components that do not allow for interactions, such as **Blank** and **Circle**, cannot be made focusable, even with the **focusable** attribute applied. 222 223 224```ts 225enabled(value: boolean) 226``` 227 228Sets the component's interactivity. If [enabled](../reference/apis-arkui/arkui-ts/ts-universal-attributes-enable.md#enabled) is set to **false**, the component becomes non-interactive and cannot gain focus. 229 230 231```ts 232visibility(value: Visibility) 233``` 234 235Sets the component's visibility. If [visibility](../reference/apis-arkui/arkui-ts/ts-universal-attributes-visibility.md#visibility) set to **Visibility.None** or **Visibility.Hidden**, the component becomes invisible and cannot gain focus. 236 237 238```ts 239focusOnTouch(value: boolean) 240``` 241 242Sets whether the component is focusable on touch. 243 244 245> **NOTE** 246> 247>When a component that is currently focused has its **focusable** or **enabled** attribute set to **false**, it automatically loses focus. The focus then shifts to another component according to the [Focus Traversal Guidelines](#focus-traversal-guidelines). 248 249 250```ts 251// xxx.ets 252@Entry 253@Component 254struct FocusableExample { 255 @State textFocusable: boolean = true; 256 @State textEnabled: boolean = true; 257 @State color1: Color = Color.Yellow; 258 @State color2: Color = Color.Yellow; 259 @State color3: Color = Color.Yellow; 260 261 build() { 262 Column({ space: 5 }) { 263 Text('Default Text') // The first Text component does not have the focusable attribute set, and is not focusable by default. 264 .borderColor(this.color1) 265 .borderWidth(2) 266 .width(300) 267 .height(70) 268 .onFocus(() => { 269 this.color1 = Color.Blue; 270 }) 271 .onBlur(() => { 272 this.color1 = Color.Yellow; 273 }) 274 Divider() 275 276 Text('focusable: ' + this.textFocusable) // The second Text component initially has focusable set to true and focusableOnTouch true. 277 .borderColor(this.color2) 278 .borderWidth(2) 279 .width(300) 280 .height(70) 281 .focusable(this.textFocusable) 282 .focusOnTouch(true) 283 .onFocus(() => { 284 this.color2 = Color.Blue; 285 }) 286 .onBlur(() => { 287 this.color2 = Color.Yellow; 288 }) 289 290 Text('enabled: ' + this.textEnabled) // The third Text component has focusable set to true, enabled initially true. 291 .borderColor(this.color3) 292 .borderWidth(2) 293 .width(300) 294 .height(70) 295 .focusable(true) 296 .enabled(this.textEnabled) 297 .focusOnTouch(true) 298 .onFocus(() => { 299 this.color3 = Color.Blue; 300 }) 301 .onBlur(() => { 302 this.color3 = Color.Yellow; 303 }) 304 305 Divider() 306 307 Row() { 308 Button('Button1') 309 .width(140).height(70) 310 Button('Button2') 311 .width(160).height(70) 312 } 313 314 Divider() 315 Button('Button3') 316 .width(300).height(70) 317 318 Divider() 319 }.width('100%').justifyContent(FlexAlign.Center) 320 .onKeyEvent((e) => { 321 // Bind onKeyEvent. When this Column component has focus, pressing F will toggle the focusable state of the second Text component. 322 if (e.keyCode === 2022 && e.type === KeyType.Down) { 323 this.textFocusable = !this.textFocusable; 324 } 325 // Bind onKeyEvent. When this Column component has focus, pressing G will toggle the enabled state of the third Text component. 326 if (e.keyCode === 2023 && e.type === KeyType.Down) { 327 this.textEnabled = !this.textEnabled; 328 } 329 }) 330 } 331} 332``` 333 334 335Operation result: 336 337 338 339 340The preceding example includes three steps: 341 342 343- As the first **Text** component does not have **focusable(true)** set, it is not focusable. 344- The second **Text** component is set with **focusOnTouch(true)**, allowing it to gain focus on touch. Pressing the **Tab** key triggers focus traversal, but the focus remains on the second component. When the **F** key is pressed, the **onKeyEvent** callback toggles **focusable** to **false**, making the second **Text** component not focusable, and the focus shifts to the next available focusable component, which is the third **Text** component. 345- Pressing the **G** key triggers the **onKeyEvent** callback, which sets **enabled** to **false**, making the third **Text** component not focusable. The focus then automatically moves to the **Row** container, where the default configuration causes the focus to shift to **Button1**. 346 347## Default Focus 348 349### Default Focus on a Page 350 351```ts 352defaultFocus(value: boolean) 353``` 354 355Specifies whether to set the component as the default focus of the page. 356 357 358```ts 359// xxx.ets 360@Entry 361@Component 362struct morenjiaodian { 363 @State oneButtonColor: Color = Color.Gray; 364 @State twoButtonColor: Color = Color.Gray; 365 @State threeButtonColor: Color = Color.Gray; 366 367 build() { 368 Column({ space: 20 }) { 369 // You can use the up and down arrow keys on an external keyboard to move the focus between the three buttons. When a button gains focus, its color changes. When it loses focus, its color changes back. 370 Button('First Button') 371 .width(260) 372 .height(70) 373 .backgroundColor(this.oneButtonColor) 374 .fontColor(Color.Black) 375 // Listen for the focus obtaining event of the first component and change its color when it obtains focus. 376 .onFocus(() => { 377 this.oneButtonColor = Color.Green; 378 }) 379 // Listen for the focus loss event of the first component and change its color when it loses focus. 380 .onBlur(() => { 381 this.oneButtonColor = Color.Gray; 382 }) 383 384 Button('Second Button') 385 .width(260) 386 .height(70) 387 .backgroundColor(this.twoButtonColor) 388 .fontColor(Color.Black) 389 // Listen for the focus obtaining event of the second component and change its color when it obtains focus. 390 .onFocus(() => { 391 this.twoButtonColor = Color.Green; 392 }) 393 // Listen for the focus loss event of the second component and change its color when it loses focus. 394 .onBlur(() => { 395 this.twoButtonColor = Color.Grey; 396 }) 397 398 Button('Third Button') 399 .width(260) 400 .height(70) 401 .backgroundColor(this.threeButtonColor) 402 .fontColor(Color.Black) 403 // Set the default focus. 404 .defaultFocus(true) 405 // Listen for the focus obtaining event of the third component and change its color when it obtains focus. 406 .onFocus(() => { 407 this.threeButtonColor = Color.Green; 408 }) 409 // Listen for the focus loss event of the third component and change its color when it loses focus. 410 .onBlur(() => { 411 this.threeButtonColor = Color.Gray ; 412 }) 413 }.width('100%').margin({ top: 20 }) 414 } 415} 416``` 417 418 419 420The preceding example includes two steps: 421 422- The **defaultFocus(true)** is set on the third **Button** component, which means it gains focus by default when the page is loaded, displaying in green. 423- Pressing the **Tab** key triggers focus traversal, and since the third **Button** component is in focus, a focus frame appears around it. 424 425### Default Focus for Containers 426 427The default focus within a container is affected by [focus priority](#focus-group-and-focus-priority). 428 429**Differences Between defaultFocus and FocusPriority** 430 431[defaultFocus](../reference/apis-arkui/arkui-ts/ts-universal-attributes-focus.md#defaultfocus9) specifies the initial focus when the page loads. [FocusPriority](../reference/apis-arkui/arkui-ts/ts-universal-attributes-focus.md#focuspriority12) defines the order in which child components gain focus within a container. Behavior is undefined when both attributes are set in some scenarios. For example, a page's initial display cannot simultaneously meet the focus requirements of a component with **defaultFocus **and a high-priority component. 432 433Example 434 435```ts 436@Entry 437@Component 438struct Index { 439 build() { 440 Row() { 441 Button('Button1') 442 .defaultFocus(true) 443 Button('Button2') 444 .focusScopePriority('RowScope', FocusPriority.PREVIOUS) 445 }.focusScopeId('RowScope') 446 } 447} 448``` 449 450### Focus Chain for Pages/Containers 451 452**Overall Focus and Non-Overall Focus** 453 454- Overall focus: The entire page or container gains focus first, then the focus shifts to its child components. Examples include page transitions, route switches within **Navigation** components, focus group traversal, and when a container component proactively calls **requestFocusById**. 455 456- Non-overall focus: A specific component gains focus, pulling its parent components into focus. Examples include a **TextInput** component proactively obtaining focus or using the **Tab** key for traversal in non-focus group. 457 458**Formation of the Focus Chain in Overall Focus** 459 4601. Initial page focus: 461 462- The leaf node of the focus chain is the node with **defaultFocus** set. 463 464- If no **defaultFocus** is configured, the focus remains on the page's root container. 465 4662. Subsequent page focus: Focus is gained by the node that last held focus. 467 4683. Focus chain with priority configuration: 469 470- If a container has a component with a focus priority higher than **PREVIOUS**, the component with the highest priority gains focus. 471 472- If no component with a priority higher than **PREVIOUS** exists, the last focused node regains focus, such as when a window refocuses after being out of focus. 473 474 475## Focus Style 476 477> **NOTE** 478> 479> When a component is in the focused state, its [zIndex](../reference/apis-arkui/arkui-ts/ts-universal-attributes-z-order.md#zindex) value is automatically elevated to **INT_MAX** to ensure that it is rendered above other components. If the component already has a specified **zIndex** value, this value will not be adjusted. When the component exits the focused state (for example, loses focus or leaves the focus chain), its **zIndex** value will revert to its original settings. 480> 481 482```ts 483focusBox(style: FocusBoxStyle) 484``` 485 486Sets the system focus box style for the component. 487 488```ts 489import { ColorMetrics, LengthMetrics } from '@kit.ArkUI' 490 491@Entry 492@Component 493struct RequestFocusExample { 494 build() { 495 Column({ space: 30 }) { 496 Button("small black focus box") 497 .focusBox({ 498 margin: new LengthMetrics(0), 499 strokeColor: ColorMetrics.rgba(0, 0, 0), 500 }) 501 Button("large red focus box") 502 .focusBox({ 503 margin: LengthMetrics.px(20), 504 strokeColor: ColorMetrics.rgba(255, 0, 0), 505 strokeWidth: LengthMetrics.px(10) 506 }) 507 } 508 .alignItems(HorizontalAlign.Center) 509 .width('100%') 510 } 511} 512``` 513 514 515 516 517The preceding example includes two steps: 518 519- After the page opens, pressing the Tab key initiates focus traversal. The first **Button** gains focus, displaying a small, black focus box that is closely fitted to the edge. 520- Pressing the Tab key again shifts focus to the second **Button**, which features a large, red focus box with a thicker stroke and a more significant margin from the edge. 521 522## Active Focus Acquisition/Loss 523 524- Using **FocusController** APIs 525 526 You are advised to use **requestFocus** from **FocusController** for actively acquiring focus. It provides the following benefits: 527 - Takes effect in the current frame, preventing interference from subsequent component tree changes. 528 - Provides exception handling, aiding in troubleshooting focus acquisition issues. 529 - Prevents errors in multi-instance scenarios by avoiding incorrect instance retrieval. 530 531 You must first obtain an instance using the [getFocusController()](../reference/apis-arkui/js-apis-arkui-UIContext.md#getfocuscontroller12) API in **UIContext** and then use this instance to call the corresponding methods. 532 533 ```ts 534 requestFocus(key: string): void 535 ``` 536 Transfers focus to a component node by the component ID, which is effective immediately. 537 538 ```ts 539 clearFocus(): void 540 ``` 541 Clears the focus and forcibly moves the focus to the root container node of the page, causing other nodes in the focus chain to lose focus. 542 543- Using **focusControl** APIs 544 ```ts 545 requestFocus(value: string): boolean 546 ``` 547 548 Moves focus to a specified component, with the change taking effect in the next frame. 549 550 551```ts 552// focusTest.ets 553@Entry 554@Component 555struct RequestExample { 556 @State btColor: string = '#ff2787d9' 557 @State btColor2: string = '#ff2787d9' 558 559 build() { 560 Column({ space: 20 }) { 561 Column({ space: 5 }) { 562 Button('Button') 563 .width(200) 564 .height(70) 565 .fontColor(Color.White) 566 .focusOnTouch(true) 567 .backgroundColor(this.btColor) 568 .onFocus(() => { 569 this.btColor = '#ffd5d5d5' 570 }) 571 .onBlur(() => { 572 this.btColor = '#ff2787d9' 573 }) 574 .id("testButton") 575 576 Button('Button') 577 .width(200) 578 .height(70) 579 .fontColor(Color.White) 580 .focusOnTouch(true) 581 .backgroundColor(this.btColor2) 582 .onFocus(() => { 583 this.btColor2 = '#ffd5d5d5' 584 }) 585 .onBlur(() => { 586 this.btColor2 = '#ff2787d9' 587 }) 588 .id("testButton2") 589 590 Divider() 591 .vertical(false) 592 .width("80%") 593 .backgroundColor('#ff707070') 594 .height(10) 595 596 Button('FocusController.requestFocus') 597 .width(200).height(70).fontColor(Color.White) 598 .onClick(() => { 599 this.getUIContext().getFocusController().requestFocus("testButton") 600 }) 601 .backgroundColor('#ff2787d9') 602 603 Button("focusControl.requestFocus") 604 .width(200).height(70).fontColor(Color.White) 605 .onClick(() => { 606 focusControl.requestFocus("testButton2") 607 }) 608 .backgroundColor('#ff2787d9') 609 610 Button("clearFocus") 611 .width(200).height(70).fontColor(Color.White) 612 .onClick(() => { 613 this.getUIContext().getFocusController().clearFocus() 614 }) 615 .backgroundColor('#ff2787d9') 616 } 617 } 618 .width('100%') 619 .height('100%') 620 } 621} 622``` 623 624 625 626The preceding example includes three steps: 627 628- When the **FocusController.requestFocus** button is clicked, the first button gains focus. 629- When the **focusControl.requestFocus** button is clicked, the second button gains focus. 630- When the **clearFocus** button is clicked, the second button loses focus. 631 632## Focus Group and Focus Priority 633 634```ts 635focusScopePriority(scopeId: string, priority?: FocusPriority) 636``` 637 638Sets the focus priority of this component in a specified container. It must be used together with **focusScopeId**. 639 640 641```ts 642focusScopeId(id: string, isGroup?: boolean) 643``` 644 645Assigns an ID to this container component and specifies whether the container is a focus group. Focus groups should not be mixed with **tabIndex** usage. 646 647```ts 648// focusTest.ets 649@Entry 650@Component 651struct FocusableExample { 652 @State inputValue: string = '' 653 654 build() { 655 Scroll() { 656 Row({ space: 20 }) { 657 Column({ space: 20 }) { // Labeled as Column1. 658 Column({ space: 5 }) { 659 Button('Group1') 660 .width(165) 661 .height(40) 662 .fontColor(Color.White) 663 Row({ space: 5 }) { 664 Button() 665 .width(80) 666 .height(40) 667 .fontColor(Color.White) 668 Button() 669 .width(80) 670 .height(40) 671 .fontColor(Color.White) 672 } 673 Row({ space: 5 }) { 674 Button() 675 .width(80) 676 .height(40) 677 .fontColor(Color.White) 678 Button() 679 .width(80) 680 .height(40) 681 .fontColor(Color.White) 682 } 683 }.borderWidth(2).borderColor(Color.Red).borderStyle(BorderStyle.Dashed) 684 Column({ space: 5 }) { 685 Button('Group2') 686 .width(165) 687 .height(40) 688 .fontColor(Color.White) 689 Row({ space: 5 }) { 690 Button() 691 .width(80) 692 .height(40) 693 .fontColor(Color.White) 694 Button() 695 .width(80) 696 .height(40) 697 .fontColor(Color.White) 698 .focusScopePriority('ColumnScope1', FocusPriority.PRIOR) // Focuses when Column1 first gains focus. 699 } 700 Row({ space: 5 }) { 701 Button() 702 .width(80) 703 .height(40) 704 .fontColor(Color.White) 705 Button() 706 .width(80) 707 .height(40) 708 .fontColor(Color.White) 709 } 710 }.borderWidth(2).borderColor(Color.Green).borderStyle(BorderStyle.Dashed) 711 } 712 .focusScopeId('ColumnScope1') 713 Column({ space: 5 }) { // Labeled as Column2. 714 TextInput({placeholder: 'input', text: this.inputValue}) 715 .onChange((value: string) => { 716 this.inputValue = value 717 }) 718 .width(156) 719 Button('Group3') 720 .width(165) 721 .height(40) 722 .fontColor(Color.White) 723 Row({ space: 5 }) { 724 Button() 725 .width(80) 726 .height(40) 727 .fontColor(Color.White) 728 Button() 729 .width(80) 730 .height(40) 731 .fontColor(Color.White) 732 } 733 Button() 734 .width(165) 735 .height(40) 736 .fontColor(Color.White) 737 .focusScopePriority('ColumnScope2', FocusPriority.PREVIOUS) // Focuses when Column2 first gains focus. 738 Row({ space: 5 }) { 739 Button() 740 .width(80) 741 .height(40) 742 .fontColor(Color.White) 743 Button() 744 .width(80) 745 .height(40) 746 .fontColor(Color.White) 747 } 748 Button() 749 .width(165) 750 .height(40) 751 .fontColor(Color.White) 752 Row({ space: 5 }) { 753 Button() 754 .width(80) 755 .height(40) 756 .fontColor(Color.White) 757 Button() 758 .width(80) 759 .height(40) 760 .fontColor(Color.White) 761 } 762 }.borderWidth(2).borderColor(Color.Orange).borderStyle(BorderStyle.Dashed) 763 .focusScopeId('ColumnScope2', true) // Column2 is a focus group. 764 }.alignItems(VerticalAlign.Top) 765 } 766 } 767} 768``` 769 770 771 772 773 774 775The preceding example includes two steps: 776 777- The **TextInput** component is part of a focus group. When the **Tab** key is pressed, the focus quickly moves out of the **TextInput** component to the next focusable element outside the group. Arrow keys can be used to move focus within the **TextInput** component. 778- The **Column** component in the upper left corner does not have a focus group set. Therefore, focus can only be traversed one by one with the **Tab** key. 779 780## Focus and Key Events 781 782When a component is in focus and has either an **onClick** or **TapGesture** event defined, pressing the **Enter** key or spacebar triggers the associated event callback. 783 784> **NOTE** 785> 786> 1. If the **onClick** or **TapGesture** event is triggered by pressing the **Enter** key or spacebar, the event does not bubble up by default. This means that the parent component's corresponding [key event](../reference/apis-arkui/arkui-ts/ts-universal-events-key.md) is not triggered synchronously. 787> 2. The key event (**onKeyEvent**) bubbles up by default, which means that it will also trigger the parent component's key event callback. 788> 3. If the component has both an **onClick** event and an **onKeyEvent**, pressing the **Enter** key or spacebar trigger both events. 789> 4. The component's response to the **onClick** event is independent of whether the focus is activated or not. 790 791``` 792@Entry 793@Component 794struct FocusOnclickExample { 795 @State count: number = 0 796 @State name: string = 'Button' 797 798 build() { 799 Column() { 800 Button(this.name) 801 .fontSize(30) 802 .onClick(() => { 803 this.count++ 804 if (this.count <= 0) { 805 this.name = "count is negative number" 806 } else if (this.count % 2 === 0) { 807 this.name = "count is even number" 808 } else { 809 this.name = "count is odd number" 810 } 811 }).height(60) 812 }.height('100%').width('100%').justifyContent(FlexAlign.Center) 813 } 814} 815``` 816 817 818## Component Focusability 819 820 821 **Table 1** Focusability of basic components 822 823| Basic Component | Focusable| Default Value of focusable| 824| ---------------------------------------- | ------- | ------------ | 825| [AlphabetIndexer](../reference/apis-arkui/arkui-ts/ts-container-alphabet-indexer.md) | Yes | true | 826| [Blank](../reference/apis-arkui/arkui-ts/ts-basic-components-blank.md) | No | false | 827| [Button](../reference/apis-arkui/arkui-ts/ts-basic-components-button.md) | Yes | true | 828| [CalendarPicker](../reference/apis-arkui/arkui-ts/ts-basic-components-calendarpicker.md) | Yes | true | 829| [Checkbox](../reference/apis-arkui/arkui-ts/ts-basic-components-checkbox.md) | Yes | true | 830| [CheckboxGroup](../reference/apis-arkui/arkui-ts/ts-basic-components-checkboxgroup.md) | Yes | true | 831| [ContainerSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-containerspan.md) | No | false | 832| [DataPanel](../reference/apis-arkui/arkui-ts/ts-basic-components-datapanel.md) | Yes | false | 833| [DatePicker](../reference/apis-arkui/arkui-ts/ts-basic-components-datepicker.md) | Yes | true | 834| [Divider](../reference/apis-arkui/arkui-ts/ts-basic-components-divider.md) | Yes | false | 835| [Gauge](../reference/apis-arkui/arkui-ts/ts-basic-components-gauge.md) | Yes | false | 836| [Image](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md) | Yes | false | 837| [ImageAnimator](../reference/apis-arkui/arkui-ts/ts-basic-components-imageanimator.md) | No | false | 838| [ImageSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-imagespan.md) | No | false | 839| [LoadingProgress](../reference/apis-arkui/arkui-ts/ts-basic-components-loadingprogress.md) | Yes | true | 840| [Marquee](../reference/apis-arkui/arkui-ts/ts-basic-components-marquee.md) | No | false | 841| [Menu](../reference/apis-arkui/arkui-ts/ts-basic-components-menu.md) | Yes | true | 842| [MenuItem](../reference/apis-arkui/arkui-ts/ts-basic-components-menuitem.md) | Yes | true | 843| [MenuItemGroup](../reference/apis-arkui/arkui-ts/ts-basic-components-menuitemgroup.md) | No | false | 844| [Navigation](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md) | Yes | true | 845| [NavRouter](../reference/apis-arkui/arkui-ts/ts-basic-components-navrouter.md) | No | false | 846| [NavDestination](../reference/apis-arkui/arkui-ts/ts-basic-components-navdestination.md) | Yes | true | 847| [PatternLock](../reference/apis-arkui/arkui-ts/ts-basic-components-patternlock.md) | Yes | true | 848| [Progress](../reference/apis-arkui/arkui-ts/ts-basic-components-progress.md) | Yes | true | 849| [QRCode](../reference/apis-arkui/arkui-ts/ts-basic-components-qrcode.md) | Yes | true | 850| [Radio](../reference/apis-arkui/arkui-ts/ts-basic-components-radio.md) | Yes | true | 851| [Rating](../reference/apis-arkui/arkui-ts/ts-basic-components-rating.md) | Yes | true | 852| [RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md) | Yes | true | 853| [RichText](../reference/apis-arkui/arkui-ts/ts-basic-components-richtext.md) | No | false | 854| [ScrollBar](../reference/apis-arkui/arkui-ts/ts-basic-components-scrollbar.md) | No | false | 855| [Search](../reference/apis-arkui/arkui-ts/ts-basic-components-search.md) | Yes | true | 856| [Select](../reference/apis-arkui/arkui-ts/ts-basic-components-select.md) | Yes | true | 857| [Slider](../reference/apis-arkui/arkui-ts/ts-basic-components-slider.md) | Yes | true | 858| [Span](../reference/apis-arkui/arkui-ts/ts-basic-components-span.md) | No | false | 859| [Stepper](../reference/apis-arkui/arkui-ts/ts-basic-components-stepper.md) | Yes | true | 860| [StepperItem](../reference/apis-arkui/arkui-ts/ts-basic-components-stepperitem.md) | Yes | true | 861| [SymbolSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-symbolSpan.md) | No | false | 862| [SymbolGlyph](../reference/apis-arkui/arkui-ts/ts-basic-components-symbolGlyph.md) | No | false | 863| [Text](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md) | Yes | false | 864| [TextArea](../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md) | No | false | 865| [TextClock](../reference/apis-arkui/arkui-ts/ts-basic-components-textclock.md) | No | false | 866| [TextInput](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md) | Yes | true | 867| [TextPicker](../reference/apis-arkui/arkui-ts/ts-basic-components-textpicker.md) | Yes | true | 868| [TextTimer](../reference/apis-arkui/arkui-ts/ts-basic-components-texttimer.md) | No | false | 869| [TimePicker](../reference/apis-arkui/arkui-ts/ts-basic-components-timepicker.md) | No | false | 870| [Toggle](../reference/apis-arkui/arkui-ts/ts-basic-components-toggle.md) | Yes | true | 871| [XComponent](../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md) | Yes | false | 872 873 **Table 2** Focusability of container components 874 875| Container Component | Focusable| Default Value of focusable| 876| ---------------------------------------- | ----- | ------------ | 877| [Badge](../reference/apis-arkui/arkui-ts/ts-container-badge.md) | No | false | 878| [Column](../reference/apis-arkui/arkui-ts/ts-container-column.md) | Yes | true | 879| [ColumnSplit](../reference/apis-arkui/arkui-ts/ts-container-columnsplit.md) | Yes | true | 880| [Counter](../reference/apis-arkui/arkui-ts/ts-container-counter.md) | Yes | false | 881| [EmbeddedComponent](../reference/apis-arkui/arkui-ts/ts-container-embedded-component.md) | No | false | 882| [Flex](../reference/apis-arkui/arkui-ts/ts-container-flex.md) | Yes | true | 883| [FlowItem](../reference/apis-arkui/arkui-ts/ts-container-flowitem.md) | Yes | true | 884| [FolderStack](../reference/apis-arkui/arkui-ts/ts-container-folderstack.md) | Yes | true | 885| [FormLink](../reference/apis-arkui/arkui-ts/ts-container-formlink.md) | No | false | 886| [GridCol](../reference/apis-arkui/arkui-ts/ts-container-gridcol.md) | Yes | true | 887| [GridRow](../reference/apis-arkui/arkui-ts/ts-container-gridrow.md) | Yes | true | 888| [Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md) | Yes | true | 889| [GridItem](../reference/apis-arkui/arkui-ts/ts-container-griditem.md) | Yes | true | 890| [Hyperlink](../reference/apis-arkui/arkui-ts/ts-container-hyperlink.md) | Yes | true | 891| [List](../reference/apis-arkui/arkui-ts/ts-container-list.md) | Yes | true | 892| [ListItem](../reference/apis-arkui/arkui-ts/ts-container-listitem.md) | Yes | true | 893| [ListItemGroup](../reference/apis-arkui/arkui-ts/ts-container-listitemgroup.md) | Yes | true | 894| [Navigator](../reference/apis-arkui/arkui-ts/ts-container-navigator.md) | Yes | true | 895| [Refresh](../reference/apis-arkui/arkui-ts/ts-container-refresh.md) | Yes | true | 896| [RelativeContainer](../reference/apis-arkui/arkui-ts/ts-container-relativecontainer.md) | No | false | 897| [Row](../reference/apis-arkui/arkui-ts/ts-container-row.md) | Yes | true | 898| [RowSplit](../reference/apis-arkui/arkui-ts/ts-container-rowsplit.md) | Yes | true | 899| [Scroll](../reference/apis-arkui/arkui-ts/ts-container-scroll.md) | Yes | true | 900| [SideBarContainer](../reference/apis-arkui/arkui-ts/ts-container-sidebarcontainer.md) | Yes | true | 901| [Stack](../reference/apis-arkui/arkui-ts/ts-container-stack.md) | Yes | true | 902| [Swiper](../reference/apis-arkui/arkui-ts/ts-container-swiper.md) | Yes | true | 903| [Tabs](../reference/apis-arkui/arkui-ts/ts-container-tabs.md) | Yes | true | 904| [TabContent](../reference/apis-arkui/arkui-ts/ts-container-tabcontent.md) | Yes | true | 905| [WaterFlow](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md) | No | false | 906| [WithTheme](../reference/apis-arkui/arkui-ts/ts-container-with-theme.md) | Yes | true | 907 908 **Table 3** Focusability of media components 909 910| Media Component | Focusable| Default Value of focusable| 911| ---------------------------------------- | ----- | ------------ | 912| [Video](../reference/apis-arkui/arkui-ts/ts-media-components-video.md) | Yes | true | 913