Skip to content

Input

A single-line text input widget.

  • Focusable
  • Container

Examples

A Simple Example

The example below shows how you might create a simple form using two Input widgets.

InputApp ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Darren ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Last Name ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

from textual.app import App, ComposeResult
from textual.widgets import Input


class InputApp(App):
    def compose(self) -> ComposeResult:
        yield Input(placeholder="First Name")
        yield Input(placeholder="Last Name")


if __name__ == "__main__":
    app = InputApp()
    app.run()

Input Types

The Input widget supports a type parameter which will prevent the user from typing invalid characters. You can set type to any of the following values:

input.type Description
"integer" Restricts input to integers.
"number" Restricts input to a floating point number.
"text" Allow all text (no restrictions).

InputApp ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ An integer ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ A number ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

from textual.app import App, ComposeResult
from textual.widgets import Input


class InputApp(App):
    def compose(self) -> ComposeResult:
        yield Input(placeholder="An integer", type="integer")
        yield Input(placeholder="A number", type="number")


if __name__ == "__main__":
    app = InputApp()
    app.run()

If you set type to something other than "text", then the Input will apply the appropriate validator.

Restricting Input

You can limit input to particular characters by supplying the restrict parameter, which should be a regular expression. The Input widget will prevent the addition of any characters that would cause the regex to no longer match. For instance, if you wanted to limit characters to binary you could set restrict=r"[01]*".

Note

The restrict regular expression is applied to the full value and not just to the new character.

Maximum Length

You can limit the length of the input by setting max_length to a value greater than zero. This will prevent the user from typing any more characters when the maximum has been reached.

Validating Input

You can supply one or more validators to the Input widget to validate the value.

All the supplied validators will run when the value changes, the Input is submitted, or focus moves out of the Input. The values "changed", "submitted", and "blur", can be passed as an iterable to the Input parameter validate_on to request that validation occur only on the respective mesages. (See InputValidationOn and Input.validate_on.) For example, the code below creates an Input widget that only gets validated when the value is submitted explicitly:

input = Input(validate_on=["submitted"])

Validation is considered to have failed if any of the validators fail.

You can check whether the validation succeeded or failed inside an Input.Changed, Input.Submitted, or Input.Blurred handler by looking at the validation_result attribute on these events.

In the example below, we show how to combine multiple validators and update the UI to tell the user why validation failed. Click the tabs to see the output for validation failures and successes.

from textual import on
from textual.app import App, ComposeResult
from textual.validation import Function, Number, ValidationResult, Validator
from textual.widgets import Input, Label, Pretty


class InputApp(App):
    # (6)!
    CSS = """
    Input.-valid {
        border: tall $success 60%;
    }
    Input.-valid:focus {
        border: tall $success;
    }
    Input {
        margin: 1 1;
    }
    Label {
        margin: 1 2;
    }
    Pretty {
        margin: 1 2;
    }
    """

    def compose(self) -> ComposeResult:
        yield Label("Enter an even number between 1 and 100 that is also a palindrome.")
        yield Input(
            placeholder="Enter a number...",
            validators=[
                Number(minimum=1, maximum=100),  # (1)!
                Function(is_even, "Value is not even."),  # (2)!
                Palindrome(),  # (3)!
            ],
        )
        yield Pretty([])

    @on(Input.Changed)
    def show_invalid_reasons(self, event: Input.Changed) -> None:
        # Updating the UI to show the reasons why validation failed
        if not event.validation_result.is_valid:  # (4)!
            self.query_one(Pretty).update(event.validation_result.failure_descriptions)
        else:
            self.query_one(Pretty).update([])


def is_even(value: str) -> bool:
    try:
        return int(value) % 2 == 0
    except ValueError:
        return False


# A custom validator
class Palindrome(Validator):  # (5)!
    def validate(self, value: str) -> ValidationResult:
        """Check a string is equal to its reverse."""
        if self.is_palindrome(value):
            return self.success()
        else:
            return self.failure("That's not a palindrome :/")

    @staticmethod
    def is_palindrome(value: str) -> bool:
        return value == value[::-1]


app = InputApp()

if __name__ == "__main__":
    app.run()
  1. Number is a built-in Validator. It checks that the value in the Input is a valid number, and optionally can check that it falls within a range.
  2. Function lets you quickly define custom validation constraints. In this case, we check the value in the Input is even.
  3. Palindrome is a custom Validator defined below.
  4. The Input.Changed event has a validation_result attribute which contains information about the validation that occurred when the value changed.
  5. Here's how we can implement a custom validator which checks if a string is a palindrome. Note how the description passed into self.failure corresponds to the message seen on UI.
  6. Textual offers default styling for the -invalid CSS class (a red border), which is automatically applied to Input when validation fails. We can also provide custom styling for the -valid class, as seen here. In this case, we add a green border around the Input to indicate successful validation.

InputApp Enter an even number between 1 and 100 that is also a palindrome. ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -23 ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ [ 'Must be between 1 and 100.', 'Value is not even.', "That's not a palindrome :/" ]

InputApp Enter an even number between 1 and 100 that is also a palindrome. ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ 44 ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ []

Textual offers several built-in validators for common requirements, but you can easily roll your own by extending Validator, as seen for Palindrome in the example above.

Validate Empty

If you set valid_empty=True then empty values will bypass any validators, and empty values will be considered valid.

Reactive Attributes

Name Type Default Description
cursor_blink bool True True if cursor blinking is enabled.
value str "" The value currently in the text input.
cursor_position int 0 The index of the cursor in the value string.
placeholder str "" The dimmed placeholder text to display when the input is empty.
password bool False True if the input should be masked.
restrict str None Optional regular expression to restrict input.
type str "text" The type of the input.
max_length int None Maximum length of the input value.
valid_empty bool False Allow empty values to bypass validation.

Messages

Bindings

The input widget defines the following bindings:

Key(s) Description
left Move the cursor left.
shift+left Move cursor left and select.
ctrl+left Move the cursor one word to the left.
right Move the cursor right or accept the completion suggestion.
ctrl+shift+left Move cursor left a word and select.
shift+right Move cursor right and select.
ctrl+right Move the cursor one word to the right.
backspace Delete the character to the left of the cursor.
ctrl+shift+right Move cursor right a word and select.
ctrl+shift+a Select all text in the input.
home,ctrl+a Go to the beginning of the input.
end,ctrl+e Go to the end of the input.
shift+home Select up to the input start.
shift+end Select up to the input end.
delete,ctrl+d Delete the character to the right of the cursor.
enter Submit the current value of the input.
ctrl+w Delete the word to the left of the cursor.
ctrl+u Delete everything to the left of the cursor.
ctrl+f Delete the word to the right of the cursor.
ctrl+k Delete everything to the right of the cursor.
ctrl+x Cut selected text.
ctrl+c Copy selected text.
ctrl+v Paste text from the clipboard.

Component Classes

The input widget provides the following component classes:

Class Description
input--cursor Target the cursor.
input--placeholder Target the placeholder text (when it exists).
input--suggestion Target the auto-completion suggestion (when it exists).
input--selection Target the selected text.

Additional Notes

  • The spacing around the text content is due to border. To remove it, set border: none; in your CSS.

Bases: ScrollView

A text input widget.

Parameters:

Name Type Description Default

value

str | None

An optional default value for the input.

None

placeholder

str

Optional placeholder text for the input.

''

highlighter

Highlighter | None

An optional highlighter for the input.

None

password

bool

Flag to say if the field should obfuscate its content.

False

restrict

str | None

A regex to restrict character inputs.

None

type

InputType

The type of the input.

'text'

max_length

int

The maximum length of the input, or 0 for no maximum length.

0

suggester

Suggester | None

Suggester associated with this input instance.

None

validators

Validator | Iterable[Validator] | None

An iterable of validators that the Input value will be checked against.

None

validate_on

Iterable[InputValidationOn] | None

Zero or more of the values "blur", "changed", and "submitted", which determine when to do input validation. The default is to do validation for all messages.

None

valid_empty

bool

Empty values are valid.

False

select_on_focus

bool

Whether to select all text on focus.

True

name

str | None

Optional name for the input widget.

None

id

str | None

Optional ID for the widget.

None

classes

str | None

Optional initial classes for the widget.

None

disabled

bool

Whether the input is disabled or not.

False

tooltip

RenderableType | None

Optional tooltip.

None

compact

bool

Enable compact style (without borders).

False

BINDINGS class-attribute

BINDINGS = [
    Binding(
        "left",
        "cursor_left",
        "Move cursor left",
        show=False,
    ),
    Binding(
        "shift+left",
        "cursor_left(True)",
        "Move cursor left and select",
        show=False,
    ),
    Binding(
        "ctrl+left",
        "cursor_left_word",
        "Move cursor left a word",
        show=False,
    ),
    Binding(
        "ctrl+shift+left",
        "cursor_left_word(True)",
        "Move cursor left a word and select",
        show=False,
    ),
    Binding(
        "right",
        "cursor_right",
        "Move cursor right or accept the completion suggestion",
        show=False,
    ),
    Binding(
        "shift+right",
        "cursor_right(True)",
        "Move cursor right and select",
        show=False,
    ),
    Binding(
        "ctrl+right",
        "cursor_right_word",
        "Move cursor right a word",
        show=False,
    ),
    Binding(
        "ctrl+shift+right",
        "cursor_right_word(True)",
        "Move cursor right a word and select",
        show=False,
    ),
    Binding(
        "backspace",
        "delete_left",
        "Delete character left",
        show=False,
    ),
    Binding(
        "ctrl+shift+a",
        "select_all",
        "Select all",
        show=False,
    ),
    Binding(
        "home,ctrl+a", "home", "Go to start", show=False
    ),
    Binding("end,ctrl+e", "end", "Go to end", show=False),
    Binding(
        "shift+home",
        "home(True)",
        "Select line start",
        show=False,
    ),
    Binding(
        "shift+end",
        "end(True)",
        "Select line end",
        show=False,
    ),
    Binding(
        "delete,ctrl+d",
        "delete_right",
        "Delete character right",
        show=False,
    ),
    Binding("enter", "submit", "Submit", show=False),
    Binding(
        "ctrl+w",
        "delete_left_word",
        "Delete left to start of word",
        show=False,
    ),
    Binding(
        "ctrl+u",
        "delete_left_all",
        "Delete all to the left",
        show=False,
    ),
    Binding(
        "ctrl+f",
        "delete_right_word",
        "Delete right to start of word",
        show=False,
    ),
    Binding(
        "ctrl+k",
        "delete_right_all",
        "Delete all to the right",
        show=False,
    ),
    Binding(
        "ctrl+x", "cut", "Cut selected text", show=False
    ),
    Binding(
        "ctrl+c", "copy", "Copy selected text", show=False
    ),
    Binding(
        "ctrl+v",
        "paste",
        "Paste text from the clipboard",
        show=False,
    ),
]
Key(s) Description
left Move the cursor left.
shift+left Move cursor left and select.
ctrl+left Move the cursor one word to the left.
right Move the cursor right or accept the completion suggestion.
ctrl+shift+left Move cursor left a word and select.
shift+right Move cursor right and select.
ctrl+right Move the cursor one word to the right.
backspace Delete the character to the left of the cursor.
ctrl+shift+right Move cursor right a word and select.
ctrl+shift+a Select all text in the input.
home,ctrl+a Go to the beginning of the input.
end,ctrl+e Go to the end of the input.
shift+home Select up to the input start.
shift+end Select up to the input end.
delete,ctrl+d Delete the character to the right of the cursor.
enter Submit the current value of the input.
ctrl+w Delete the word to the left of the cursor.
ctrl+u Delete everything to the left of the cursor.
ctrl+f Delete the word to the right of the cursor.
ctrl+k Delete everything to the right of the cursor.
ctrl+x Cut selected text.
ctrl+c Copy selected text.
ctrl+v Paste text from the clipboard.

COMPONENT_CLASSES class-attribute

COMPONENT_CLASSES = {
    "input--cursor",
    "input--placeholder",
    "input--suggestion",
    "input--selection",
}
Class Description
input--cursor Target the cursor.
input--placeholder Target the placeholder text (when it exists).
input--suggestion Target the auto-completion suggestion (when it exists).
input--selection Target the selected text.

compact class-attribute instance-attribute

compact = compact

Make the input compact (without borders).

content_width property

content_width

The width of the content.

cursor_at_end property

cursor_at_end

Flag to indicate if the cursor is at the end.

cursor_at_start property

cursor_at_start

Flag to indicate if the cursor is at the start.

cursor_position property writable

cursor_position

The current position of the cursor, corresponding to the end of the selection.

cursor_screen_offset property

cursor_screen_offset

The offset of the cursor of this input in screen-space. (x, y)/(column, row).

is_valid property

is_valid

Check if the value has passed validation.

max_length class-attribute instance-attribute

max_length = max_length

The maximum length of the input, in characters.

restrict class-attribute instance-attribute

restrict = restrict

A regular expression to limit changes in value.

selected_text property

selected_text

The text between the start and end points of the current selection.

selection class-attribute instance-attribute

selection = reactive(cursor(0))

The currently selected range of text.

suggester instance-attribute

suggester = suggester

The suggester used to provide completions as the user types.

type class-attribute instance-attribute

type = type

The type of the input.

valid_empty class-attribute instance-attribute

valid_empty = var(False)

Empty values should pass validation.

validate_on instance-attribute

validate_on = (
    _POSSIBLE_VALIDATE_ON_VALUES & set(validate_on)
    if validate_on is not None
    else _POSSIBLE_VALIDATE_ON_VALUES
)

Set with event names to do input validation on.

Validation can only be performed on blur, on input changes and on input submission.

Example

This creates an Input widget that only gets validated when the value is submitted explicitly:

input = Input(validate_on=["submitted"])

Blurred dataclass

Blurred(input, value, validation_result=None)

Bases: