# TextInput

> TextInput is a one-line text field with a label above it and an error line below it, holding the typed text itself and passing on only valid text.

URL: https://xichil.dev/docs/xis-mvui/v1/widgets/text-input/ · Updated: 2026-11-06 · Applies to: Fabric, Quilt, Legacy Fabric, Forge, NeoForge, MC 1.7.10 - 26.3

A one-line text field with a label above it and an error line below it, like the name field of vanilla's
world-creation screen.

```java
TextInput name = TextInput.builder("name")
        .label(Text.translatable("mymod.name", "Profile name"))
        .initial(config.profileName)
        .maxLength(32)
        .validator(s -> s.trim().isEmpty() ? Text.translatable("mymod.name.empty", "Enter a name") : null)
        .onChange(s -> config.profileName = s)
        .build();
```

## Builder

| Method | Required | Default | Notes |
| --- | --- | --- | --- |
| `label(Supplier<Text>)` / `label(Text)` | yes | | the text above the field |
| `initial(String)` | no | `""` | the starting text, usually your current value; cut to `maxLength`; not passed to `onChange` |
| `maxLength(int)` | no | `64` | the most characters the field accepts; must be positive |
| `validator(Function<String, Text>)` | no | every text is valid | returns an error, or `null` for valid text. Runs after every edit and refresh: keep it fast. |
| `onChange(Consumer<String>)` | no | does nothing | receives the text after each edit that leaves it valid; main thread |
| `enabled`, `tooltip`, `visible` | no | | [options every widget has](https://xichil.dev/docs/xis-mvui/v1/widgets/index.md#options-every-widget-has) |

## Methods

| Method | Does |
| --- | --- |
| `value()` | the text in the field now, valid or not; never `null` |
| `isValid()` | whether the current text is valid (`error()` is `null`) |
| `error()` | the validator's error for the current text, or `null` |
| `setValue(String)` | replaces the text (cut to `maxLength`; `null` counts as empty) and calls `onChange` if it's valid. For example `setValue("")` clears the field. |

## Behaviour

- **The typed text lives in the entry**, not in your code: the field starts with `initial`, and a refresh
  doesn't reset it. That way invalid input stays while the player fixes it
  ([State and refresh](https://xichil.dev/docs/xis-mvui/v1/concepts/state-and-refresh/index.md)).
- `onChange` never sees invalid text. Alternatively, an action reads `value()` when it runs, such as a Create
  button that is enabled only while `name.isValid()`.
- For numbers use a [NumberField](https://xichil.dev/docs/xis-mvui/v1/widgets/number-field/index.md); for several lines a [MultiLineInput](https://xichil.dev/docs/xis-mvui/v1/widgets/multi-line-input/index.md).
- **Footer:** yes.

## Test it

```java
host.type("name", "");
assertTrue(host.render().contains("[input name] Profile name: \"\" (error: Enter a name)"));
```

## See also

- Javadoc: [TextInput](https://xichil.dev/javadoc/xis-mvui/v1/dev/xichil/mvui/TextInput.html)
- [Validate what players type](https://xichil.dev/docs/xis-mvui/v1/guides/validation/index.md)
