From 298d30058ec836f23be1b22b2552aa12ba7832fa Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Thu, 25 Jun 2026 12:22:10 +0400 Subject: [PATCH 1/2] feat: add inputMode API to TextField Add setInputMode/getInputMode and an InputMode enum so the virtual keyboard hint can be set for mobile devices. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../flow/component/textfield/InputMode.java | 77 +++++++++++++++++++ .../flow/component/textfield/TextField.java | 33 ++++++++ .../textfield/tests/TextFieldTest.java | 21 +++++ 3 files changed, 131 insertions(+) create mode 100644 vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java new file mode 100644 index 00000000000..396c754786c --- /dev/null +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2026 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.component.textfield; + +/** + * Virtual keyboard hints for the {@code inputmode} attribute. They tell the + * browser which type of virtual keyboard to display when the user interacts + * with the field on a mobile device. + * + * @see + * inputmode attribute + */ +public enum InputMode { + + /** + * No virtual keyboard. Useful when the field implements its own keyboard + * input control. + */ + NONE("none"), + + /** + * Standard text input keyboard for the user's current locale. + */ + TEXT("text"), + + /** + * Fractional numeric input keyboard that includes the digits and the + * decimal separator for the user's locale. + */ + DECIMAL("decimal"), + + /** + * Numeric input keyboard that only requires the digits 0–9. + */ + NUMERIC("numeric"), + + /** + * Telephone keypad input, including the digits 0–9, the asterisk (*), + * and the pound (#) key. + */ + TEL("tel"), + + /** + * Virtual keyboard optimized for search input. + */ + SEARCH("search"), + + /** + * Virtual keyboard optimized for entering email addresses. + */ + EMAIL("email"), + + /** + * Virtual keyboard optimized for entering URLs. + */ + URL("url"); + + final String value; + + InputMode(String value) { + this.value = value; + } +} diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java index 2368f3130b9..343249c087b 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java @@ -383,6 +383,39 @@ public String getPattern() { return getElement().getProperty("pattern"); } + /** + * Sets the {@link InputMode} that hints at the type of virtual keyboard to + * display when the user interacts with the field on a mobile device. If not + * set, the browser defaults to {@link InputMode#TEXT}. + * + * @param inputMode + * the {@code inputmode} value, or {@code null} to unset + * @see + * inputmode attribute + */ + public void setInputMode(InputMode inputMode) { + if (inputMode == null) { + getElement().removeProperty("inputMode"); + } else { + getElement().setProperty("inputMode", inputMode.value); + } + } + + /** + * Gets the {@link InputMode} of the field. + * + * @return the {@code inputmode} value, or {@code null} if not set + * @see #setInputMode(InputMode) + */ + public InputMode getInputMode() { + String inputMode = getElement().getProperty("inputMode"); + if (inputMode == null || inputMode.isEmpty()) { + return null; + } + return InputMode.valueOf(inputMode.toUpperCase()); + } + @Override public String getEmptyValue() { return ""; diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java index 87edce0f922..850325f642b 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java @@ -30,6 +30,7 @@ import com.vaadin.flow.component.shared.HasThemeVariant; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; +import com.vaadin.flow.component.textfield.InputMode; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextFieldVariant; import com.vaadin.flow.di.Instantiator; @@ -114,6 +115,26 @@ void autoselectPropertyValue() { assertAutoselectPropertyValueEquals(textField, false); } + @Test + void inputMode_defaultsToNull() { + TextField textField = new TextField(); + Assertions.assertNull(textField.getInputMode()); + } + + @Test + void setInputMode_getInputMode() { + TextField textField = new TextField(); + + textField.setInputMode(InputMode.NUMERIC); + Assertions.assertEquals(InputMode.NUMERIC, textField.getInputMode()); + Assertions.assertEquals("numeric", + textField.getElement().getProperty("inputMode")); + + textField.setInputMode(null); + Assertions.assertNull(textField.getInputMode()); + Assertions.assertNull(textField.getElement().getProperty("inputMode")); + } + @Test void elementHasValue_wrapIntoTextField_propertyIsNotSetToInitialValue() { ComponentFromTest From 7faeed3312a5b480b45a92d2d8a127f51446080e Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 29 Jun 2026 10:35:41 +0400 Subject: [PATCH 2/2] docs: add @since 25.3 to TextField inputMode API Co-Authored-By: Claude Opus 4.8 (1M context) --- .../java/com/vaadin/flow/component/textfield/InputMode.java | 1 + .../java/com/vaadin/flow/component/textfield/TextField.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java index 396c754786c..3e1b8fb2d25 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/InputMode.java @@ -23,6 +23,7 @@ * @see * inputmode attribute + * @since 25.3 */ public enum InputMode { diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java index 343249c087b..fcd0acecd5b 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextField.java @@ -393,6 +393,7 @@ public String getPattern() { * @see * inputmode attribute + * @since 25.3 */ public void setInputMode(InputMode inputMode) { if (inputMode == null) { @@ -407,6 +408,7 @@ public void setInputMode(InputMode inputMode) { * * @return the {@code inputmode} value, or {@code null} if not set * @see #setInputMode(InputMode) + * @since 25.3 */ public InputMode getInputMode() { String inputMode = getElement().getProperty("inputMode");