From 92979da38bb5bc087d2c9024e2263e94afb57623 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sat, 4 Apr 2026 01:54:22 +0530 Subject: [PATCH 01/13] feat(types): add InputMode enum for HTML5 inputmode attribute support --- .../src/widgets/BaseInputWidget/constants.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/client/src/widgets/BaseInputWidget/constants.ts b/app/client/src/widgets/BaseInputWidget/constants.ts index 0e678e8181cb..9aa7c25510f6 100644 --- a/app/client/src/widgets/BaseInputWidget/constants.ts +++ b/app/client/src/widgets/BaseInputWidget/constants.ts @@ -13,3 +13,25 @@ export enum NumberInputStepButtonPosition { RIGHT = "right", NONE = "none", } + +/** + * HTML5 inputmode attribute values + * Controls the virtual keyboard displayed on mobile devices + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ +export enum InputMode { + // Shows numeric keypad with 0-9 + NUMERIC = "numeric", + // Shows numeric keypad with 0-9 and decimal point (.) + DECIMAL = "decimal", + // Shows phone keypad with 0-9, *, # and standard dial keys + TEL = "tel", + // Shows email keyboard with @, period, and other email-related keys + EMAIL = "email", + // Shows default text keyboard + TEXT = "text", + // Shows search optimized keyboard + SEARCH = "search", + // Shows URL optimized keyboard with / and .com + URL = "url", +} From 8f241962badab37f7d46085817ab6055165d3004 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sat, 4 Apr 2026 01:54:58 +0530 Subject: [PATCH 02/13] feat(input): add inputmode mapping for mobile keyboard optimization --- .../BaseInputWidget/component/index.tsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index 7675510ac32d..7727dad70416 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -500,6 +500,28 @@ class BaseInputComponent extends React.Component< } } + /** + * Maps input type to appropriate HTML5 inputmode attribute for mobile keyboards + * Provides optimal keyboard experience across iOS and Android + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ + getInputMode(inputType: InputHTMLType = "TEXT"): string | undefined { + switch (inputType) { + // Show decimal point keypad for currency and numeric inputs + case "NUMBER": + return "decimal"; + // Show phone keypad (+, -, *, #) for telephone inputs + case "TEL": + return "tel"; + // Show email keypad with @ and . symbols + case "EMAIL": + return "email"; + // Default: let browser decide based on input element type + default: + return undefined; + } + } + onKeyDownTextArea = (e: React.KeyboardEvent) => { const isEnterKey = e.key === "Enter" || e.keyCode === 13; @@ -606,6 +628,7 @@ class BaseInputComponent extends React.Component< (this.props.rtl ? " rtl" : "") } disabled={this.props.disabled} + inputMode={this.getInputMode(this.props.inputHTMLType)} inputRef={this.props.inputRef as IRef} intent={this.props.intent} leftIcon={this.getLeftIcon()} From 45039fd9194da39bd98f9eb5fe167346c8d08872 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sat, 4 Apr 2026 01:55:13 +0530 Subject: [PATCH 03/13] fix(currency-input): enable numeric keypad on iOS with inputmode support --- app/client/src/widgets/CurrencyInputWidget/component/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index 38ffef709236..c32e3e1a558a 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -49,6 +49,9 @@ class CurrencyInputComponent extends React.Component Date: Sat, 4 Apr 2026 01:54:22 +0530 Subject: [PATCH 04/13] feat(types): add InputMode enum for HTML5 inputmode attribute support --- .../src/widgets/BaseInputWidget/constants.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/client/src/widgets/BaseInputWidget/constants.ts b/app/client/src/widgets/BaseInputWidget/constants.ts index 0e678e8181cb..9aa7c25510f6 100644 --- a/app/client/src/widgets/BaseInputWidget/constants.ts +++ b/app/client/src/widgets/BaseInputWidget/constants.ts @@ -13,3 +13,25 @@ export enum NumberInputStepButtonPosition { RIGHT = "right", NONE = "none", } + +/** + * HTML5 inputmode attribute values + * Controls the virtual keyboard displayed on mobile devices + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ +export enum InputMode { + // Shows numeric keypad with 0-9 + NUMERIC = "numeric", + // Shows numeric keypad with 0-9 and decimal point (.) + DECIMAL = "decimal", + // Shows phone keypad with 0-9, *, # and standard dial keys + TEL = "tel", + // Shows email keyboard with @, period, and other email-related keys + EMAIL = "email", + // Shows default text keyboard + TEXT = "text", + // Shows search optimized keyboard + SEARCH = "search", + // Shows URL optimized keyboard with / and .com + URL = "url", +} From 84c68a2a5f8d8569be0128209249d237e96b9695 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sat, 4 Apr 2026 01:54:58 +0530 Subject: [PATCH 05/13] feat(input): add inputmode mapping for mobile keyboard optimization --- .../BaseInputWidget/component/index.tsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index 7675510ac32d..7727dad70416 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -500,6 +500,28 @@ class BaseInputComponent extends React.Component< } } + /** + * Maps input type to appropriate HTML5 inputmode attribute for mobile keyboards + * Provides optimal keyboard experience across iOS and Android + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ + getInputMode(inputType: InputHTMLType = "TEXT"): string | undefined { + switch (inputType) { + // Show decimal point keypad for currency and numeric inputs + case "NUMBER": + return "decimal"; + // Show phone keypad (+, -, *, #) for telephone inputs + case "TEL": + return "tel"; + // Show email keypad with @ and . symbols + case "EMAIL": + return "email"; + // Default: let browser decide based on input element type + default: + return undefined; + } + } + onKeyDownTextArea = (e: React.KeyboardEvent) => { const isEnterKey = e.key === "Enter" || e.keyCode === 13; @@ -606,6 +628,7 @@ class BaseInputComponent extends React.Component< (this.props.rtl ? " rtl" : "") } disabled={this.props.disabled} + inputMode={this.getInputMode(this.props.inputHTMLType)} inputRef={this.props.inputRef as IRef} intent={this.props.intent} leftIcon={this.getLeftIcon()} From 39310aa1af809f924e653ab41cef4debbfb9c726 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sat, 4 Apr 2026 01:55:13 +0530 Subject: [PATCH 06/13] fix(currency-input): enable numeric keypad on iOS with inputmode support --- app/client/src/widgets/CurrencyInputWidget/component/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index 38ffef709236..c32e3e1a558a 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -49,6 +49,9 @@ class CurrencyInputComponent extends React.Component Date: Thu, 23 Apr 2026 14:53:15 +0530 Subject: [PATCH 07/13] test: add getInputMode unit tests and use InputMode enum --- .../component/_tests_/getInputMode.test.ts | 20 +++++++++++++++++++ .../BaseInputWidget/component/index.tsx | 10 +++++----- .../src/widgets/BaseInputWidget/constants.ts | 1 + .../CurrencyInputWidget/component/index.tsx | 5 ++--- 4 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts diff --git a/app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts b/app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts new file mode 100644 index 000000000000..3bc327507287 --- /dev/null +++ b/app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts @@ -0,0 +1,20 @@ +import { InputMode } from "../../constants"; +import { getInputMode } from "../index"; + +describe("getInputMode", () => { + it('maps NUMBER to InputMode.DECIMAL ("decimal")', () => { + expect(getInputMode("NUMBER")).toBe(InputMode.DECIMAL); + }); + + it('maps TEL to InputMode.TEL ("tel")', () => { + expect(getInputMode("TEL")).toBe(InputMode.TEL); + }); + + it('maps EMAIL to InputMode.EMAIL ("email")', () => { + expect(getInputMode("EMAIL")).toBe(InputMode.EMAIL); + }); + + it("returns undefined for default/unknown type", () => { + expect(getInputMode("TEXT")).toBeUndefined(); + }); +}); \ No newline at end of file diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index 7727dad70416..a1d8c39b71b6 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -17,7 +17,7 @@ import { createMessage, INPUT_WIDGET_DEFAULT_VALIDATION_ERROR, } from "ee/constants/messages"; -import type { NumberInputStepButtonPosition } from "../constants"; +import type { InputMode, NumberInputStepButtonPosition } from "../constants"; import { InputTypes } from "../constants"; // TODO(abhinav): All of the following imports should not be in widgets. @@ -505,17 +505,17 @@ class BaseInputComponent extends React.Component< * Provides optimal keyboard experience across iOS and Android * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode */ - getInputMode(inputType: InputHTMLType = "TEXT"): string | undefined { + getInputMode(inputType: InputHTMLType = "TEXT"): InputMode | undefined { switch (inputType) { // Show decimal point keypad for currency and numeric inputs case "NUMBER": - return "decimal"; + return InputMode.DECIMAL; // Show phone keypad (+, -, *, #) for telephone inputs case "TEL": - return "tel"; + return InputMode.TEL; // Show email keypad with @ and . symbols case "EMAIL": - return "email"; + return InputMode.EMAIL; // Default: let browser decide based on input element type default: return undefined; diff --git a/app/client/src/widgets/BaseInputWidget/constants.ts b/app/client/src/widgets/BaseInputWidget/constants.ts index 9aa7c25510f6..ab270318247f 100644 --- a/app/client/src/widgets/BaseInputWidget/constants.ts +++ b/app/client/src/widgets/BaseInputWidget/constants.ts @@ -22,6 +22,7 @@ export enum NumberInputStepButtonPosition { export enum InputMode { // Shows numeric keypad with 0-9 NUMERIC = "numeric", + NONE = "none", // Shows numeric keypad with 0-9 and decimal point (.) DECIMAL = "decimal", // Shows phone keypad with 0-9, *, # and standard dial keys diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index c32e3e1a558a..7cfcdc59d393 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -49,9 +49,8 @@ class CurrencyInputComponent extends React.Component Date: Tue, 28 Apr 2026 13:27:16 +0530 Subject: [PATCH 08/13] test: move getInputMode test under __tests__ --- .../component/{_tests_ => __tests__}/getInputMode.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/client/src/widgets/BaseInputWidget/component/{_tests_ => __tests__}/getInputMode.test.ts (100%) diff --git a/app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts similarity index 100% rename from app/client/src/widgets/BaseInputWidget/component/_tests_/getInputMode.test.ts rename to app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts From cf3dc6761e633784433647640fc95a4eb90ad063 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Tue, 28 Apr 2026 13:45:52 +0530 Subject: [PATCH 09/13] fix: add InputMode.NONE for HTML inputmode --- app/client/src/widgets/BaseInputWidget/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/client/src/widgets/BaseInputWidget/constants.ts b/app/client/src/widgets/BaseInputWidget/constants.ts index ab270318247f..55906ac3694b 100644 --- a/app/client/src/widgets/BaseInputWidget/constants.ts +++ b/app/client/src/widgets/BaseInputWidget/constants.ts @@ -6,6 +6,7 @@ export enum InputTypes { EMAIL = "EMAIL", PASSWORD = "PASSWORD", CURRENCY = "CURRENCY", + NONE = "none", } export enum NumberInputStepButtonPosition { From f502be07f2ae6ff50e91361da782fedee566f997 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Tue, 28 Apr 2026 13:52:18 +0530 Subject: [PATCH 10/13] refactor: export getInputMode helper for tests --- .../BaseInputWidget/component/index.tsx | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index a1d8c39b71b6..cbb1a8c45a52 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -424,6 +424,26 @@ export const isNumberInputType = (inputHTMLType: InputHTMLType = "TEXT") => { return inputHTMLType === "NUMBER"; }; +/** + * Maps input type to appropriate HTML5 inputmode attribute for mobile keyboards + * Provides optimal keyboard experience across iOS and Android + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ +export const getInputMode = ( + inputType: InputHTMLType = "TEXT", +): InputMode | undefined => { + switch (inputType) { + case "NUMBER": + return InputMode.DECIMAL; + case "TEL": + return InputMode.TEL; + case "EMAIL": + return InputMode.EMAIL; + default: + return undefined; + } +}; + class BaseInputComponent extends React.Component< BaseInputComponentProps, InputComponentState @@ -500,27 +520,11 @@ class BaseInputComponent extends React.Component< } } - /** - * Maps input type to appropriate HTML5 inputmode attribute for mobile keyboards - * Provides optimal keyboard experience across iOS and Android - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode - */ - getInputMode(inputType: InputHTMLType = "TEXT"): InputMode | undefined { - switch (inputType) { - // Show decimal point keypad for currency and numeric inputs - case "NUMBER": - return InputMode.DECIMAL; - // Show phone keypad (+, -, *, #) for telephone inputs - case "TEL": - return InputMode.TEL; - // Show email keypad with @ and . symbols - case "EMAIL": - return InputMode.EMAIL; - // Default: let browser decide based on input element type - default: - return undefined; - } - } + private getInputMode = ( + inputType: InputHTMLType = "TEXT", + ): InputMode | undefined => { + return getInputMode(inputType); + }; onKeyDownTextArea = (e: React.KeyboardEvent) => { const isEnterKey = e.key === "Enter" || e.keyCode === 13; From 73c0b02abe3d7ceee751aed45febda9c9991a382 Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Tue, 28 Apr 2026 23:15:03 +0530 Subject: [PATCH 11/13] chore: fix lint/prettier and stabilize getInputMode tests --- .../component/__tests__/getInputMode.test.ts | 7 ++++++- app/client/src/widgets/BaseInputWidget/component/index.tsx | 4 ++-- .../src/widgets/CurrencyInputWidget/component/index.tsx | 4 +--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts index 3bc327507287..4c71072767b0 100644 --- a/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts +++ b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts @@ -17,4 +17,9 @@ describe("getInputMode", () => { it("returns undefined for default/unknown type", () => { expect(getInputMode("TEXT")).toBeUndefined(); }); -}); \ No newline at end of file +}); +expect(getInputMode()).toBeUndefined(); + +function expect(arg0: InputMode | undefined) { + throw new Error("Function not implemented."); +} diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index cbb1a8c45a52..b7f1f1a51986 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -17,8 +17,8 @@ import { createMessage, INPUT_WIDGET_DEFAULT_VALIDATION_ERROR, } from "ee/constants/messages"; -import type { InputMode, NumberInputStepButtonPosition } from "../constants"; -import { InputTypes } from "../constants"; +import { InputMode, InputTypes } from "../constants"; +import type { NumberInputStepButtonPosition } from "../constants"; // TODO(abhinav): All of the following imports should not be in widgets. import ErrorTooltip from "components/editorComponents/ErrorTooltip"; diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index 7cfcdc59d393..bc2dca3865fd 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -48,9 +48,7 @@ class CurrencyInputComponent extends React.Component Date: Sun, 3 May 2026 15:21:06 +0530 Subject: [PATCH 12/13] test: fix getInputMode test --- .../component/__tests__/getInputMode.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts index 4c71072767b0..58b2625e46c3 100644 --- a/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts +++ b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts @@ -15,11 +15,7 @@ describe("getInputMode", () => { }); it("returns undefined for default/unknown type", () => { + expect(getInputMode()).toBeUndefined(); expect(getInputMode("TEXT")).toBeUndefined(); }); -}); -expect(getInputMode()).toBeUndefined(); - -function expect(arg0: InputMode | undefined) { - throw new Error("Function not implemented."); -} +}); \ No newline at end of file From aece43cc3a8913f76c5f6f8144c83949247f4e4b Mon Sep 17 00:00:00 2001 From: Arbab1308 Date: Sun, 3 May 2026 15:23:20 +0530 Subject: [PATCH 13/13] chore: fix lint/prettier and getInputMode tests --- app/client/src/widgets/CurrencyInputWidget/component/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index bc2dca3865fd..e6371e4ea489 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -102,3 +102,5 @@ export interface CurrencyInputComponentProps extends BaseInputComponentProps { } export default CurrencyInputComponent; + +expect(getInputMode()).toBeUndefined(); \ No newline at end of file