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..3e1b8fb2d25
--- /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,78 @@
+/*
+ * 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
+ * @since 25.3
+ */
+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..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
@@ -383,6 +383,41 @@ 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
+ * @since 25.3
+ */
+ 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)
+ * @since 25.3
+ */
+ 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