From fb25944377f2fdfb016d4d4481613dd352a77f0d Mon Sep 17 00:00:00 2001 From: ilhan007 Date: Wed, 29 Oct 2025 13:40:02 +0200 Subject: [PATCH 1/2] feat(ui5-input | textarea): support autofocus attribute --- packages/main/cypress/specs/Input.cy.tsx | 7 +++++++ packages/main/src/Input.ts | 4 ++++ packages/main/src/Popup.ts | 17 +++++++++++++---- packages/main/src/TextArea.ts | 4 ++++ packages/main/test/pages/Dialog.html | 1 + packages/main/test/pages/Input.html | 3 +++ packages/main/test/pages/Popover.html | 10 ++++++++++ 7 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/main/cypress/specs/Input.cy.tsx b/packages/main/cypress/specs/Input.cy.tsx index 4081a16b5e9f..bf58ae6318fa 100644 --- a/packages/main/cypress/specs/Input.cy.tsx +++ b/packages/main/cypress/specs/Input.cy.tsx @@ -1284,6 +1284,13 @@ describe("Change event behavior when selecting the same suggestion item", () => }); describe("Accessibility", () => { + it("tests autofocus attribute", () => { + cy.mount(); + + cy.get("[ui5-input]") + .should("be.focused"); + }); + it("tests accessibleDescription property", () => { cy.mount(); diff --git a/packages/main/src/Input.ts b/packages/main/src/Input.ts index 08da1a4eaa1b..727b5fb4b9bb 100644 --- a/packages/main/src/Input.ts +++ b/packages/main/src/Input.ts @@ -214,6 +214,7 @@ type InputSuggestionScrollEventDetail = { ValueStateMessageCss, SuggestionsCss, ], + shadowRootOptions: { delegatesFocus: true }, }) /** @@ -720,6 +721,9 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement ResizeHandler.register(this, this._handleResizeBound); registerUI5Element(this, this._updateAssociatedLabelsTexts.bind(this)); this._enableComposition(); + if (this.hasAttribute("autofocus")) { + requestAnimationFrame(() => this.focus()); + } } onExitDOM() { diff --git a/packages/main/src/Popup.ts b/packages/main/src/Popup.ts index fda670bdff31..1c7fbc1465d9 100644 --- a/packages/main/src/Popup.ts +++ b/packages/main/src/Popup.ts @@ -504,13 +504,18 @@ abstract class Popup extends UI5Element { * @returns Promise that resolves when the focus is applied */ async applyFocus(): Promise { - // do nothing if the standard HTML autofocus is used - if (this.querySelector("[autofocus]")) { + await this._waitForDomRef(); + + const elementWithAutoFocus = this.querySelector("[autofocus]"); + if (elementWithAutoFocus) { + // If the "autofocus" is set on UI5Element, focus it manually. + if ("isUI5Element" in elementWithAutoFocus) { + (elementWithAutoFocus as UI5Element).focus(); + } + // Otherwise, the browser will focus it automatically. return; } - await this._waitForDomRef(); - if (this.getRootNode() === this) { return; } @@ -709,5 +714,9 @@ abstract class Popup extends UI5Element { } } +function instanceOfUI5Element(object: any): object is UI5Element { + return "isUI5Element" in object; +} + export default Popup; export type { PopupScrollEventDetail, PopupBeforeCloseEventDetail }; diff --git a/packages/main/src/TextArea.ts b/packages/main/src/TextArea.ts index 1129a86b8f97..613c7f5fb299 100644 --- a/packages/main/src/TextArea.ts +++ b/packages/main/src/TextArea.ts @@ -83,6 +83,7 @@ type TextAreaInputEventDetail = { ], renderer: jsxRenderer, template: TextAreaTemplate, + shadowRootOptions: { delegatesFocus: true }, }) /** * Fired when the text has changed and the focus leaves the component. @@ -377,6 +378,9 @@ class TextArea extends UI5Element implements IFormInputElement { onEnterDOM() { ResizeHandler.register(this, this._fnOnResize); + if (this.hasAttribute("autofocus")) { + requestAnimationFrame(() => this.focus()); + } } onExitDOM() { diff --git a/packages/main/test/pages/Dialog.html b/packages/main/test/pages/Dialog.html index 119577f212e3..ba919341096e 100644 --- a/packages/main/test/pages/Dialog.html +++ b/packages/main/test/pages/Dialog.html @@ -103,6 +103,7 @@
Close
+ diff --git a/packages/main/test/pages/Input.html b/packages/main/test/pages/Input.html index 4e18da99c108..46219d4562c2 100644 --- a/packages/main/test/pages/Input.html +++ b/packages/main/test/pages/Input.html @@ -22,6 +22,9 @@

Input with suggestions: type 'a'

Event [selectionChange] :: N/A
+

Input with autofocus

+ +

Input in Cozy

diff --git a/packages/main/test/pages/Popover.html b/packages/main/test/pages/Popover.html index dbf1b8fec06c..d87c066cdcd0 100644 --- a/packages/main/test/pages/Popover.html +++ b/packages/main/test/pages/Popover.html @@ -96,6 +96,13 @@ Close with Attribute + Open with Attribute + + Close with Method + Close with Attribute + + +

@@ -666,6 +673,9 @@

Popover in ShadowRoot, Opener set as ID in window.document

btnOpenWithAttr.addEventListener("click", function () { popoverAttr.setAttribute("open", ""); }); + btnOpenWithAttr2.addEventListener("click", function () { + popoverAttr2.setAttribute("open", ""); + }); btnCloseWithMethod.addEventListener("click", function () { popoverAttr.open = false; From e56dc4513b8f880d50d034bf9b4643e5b1a21ea6 Mon Sep 17 00:00:00 2001 From: ilhan007 Date: Wed, 29 Oct 2025 13:59:37 +0200 Subject: [PATCH 2/2] chore: lint --- packages/main/src/Input.ts | 2 +- packages/main/src/Popup.ts | 6 +----- packages/main/src/TextArea.ts | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/main/src/Input.ts b/packages/main/src/Input.ts index 727b5fb4b9bb..ec0c0f13297b 100644 --- a/packages/main/src/Input.ts +++ b/packages/main/src/Input.ts @@ -722,7 +722,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement registerUI5Element(this, this._updateAssociatedLabelsTexts.bind(this)); this._enableComposition(); if (this.hasAttribute("autofocus")) { - requestAnimationFrame(() => this.focus()); + this.focus(); } } diff --git a/packages/main/src/Popup.ts b/packages/main/src/Popup.ts index 1c7fbc1465d9..6f9cd2d51364 100644 --- a/packages/main/src/Popup.ts +++ b/packages/main/src/Popup.ts @@ -505,7 +505,7 @@ abstract class Popup extends UI5Element { */ async applyFocus(): Promise { await this._waitForDomRef(); - + const elementWithAutoFocus = this.querySelector("[autofocus]"); if (elementWithAutoFocus) { // If the "autofocus" is set on UI5Element, focus it manually. @@ -714,9 +714,5 @@ abstract class Popup extends UI5Element { } } -function instanceOfUI5Element(object: any): object is UI5Element { - return "isUI5Element" in object; -} - export default Popup; export type { PopupScrollEventDetail, PopupBeforeCloseEventDetail }; diff --git a/packages/main/src/TextArea.ts b/packages/main/src/TextArea.ts index 46a239c46f79..3892c82b1bcc 100644 --- a/packages/main/src/TextArea.ts +++ b/packages/main/src/TextArea.ts @@ -379,7 +379,7 @@ class TextArea extends UI5Element implements IFormInputElement { onEnterDOM() { ResizeHandler.register(this, this._fnOnResize); if (this.hasAttribute("autofocus")) { - requestAnimationFrame(() => this.focus()); + this.focus(); } }