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()

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 or Input.Submitted 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.

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 str The dimmed placeholder text to display when the input is empty.
password bool False True if the input should be masked.

Messages

Bindings

The input widget defines the following bindings:

Key(s) Description
left Move the cursor left.
ctrl+left Move the cursor one word to the left.
right Move the cursor right or accept the completion suggestion.
ctrl+right Move the cursor one word to the right.
backspace Delete the character to the left of the cursor.
home,ctrl+a Go to the beginning of the input.
end,ctrl+e Go to the end of the input.
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.

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).

Additional Notes

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

textual.widgets.Input class

def __init__(
    self,
    value=None,
    placeholder="",
    highlighter=None,
    password=False,
    *,
    suggester=None,
    validators=None,
    validate_on=None,
    name=None,
    id=None,
    classes=None,
    disabled=False
):

Bases: Widget

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
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
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

BINDINGS class-attribute

BINDINGS: list[BindingType] = [
    Binding(
        "left", "cursor_left", "cursor left", show=False
    ),
    Binding(
        "ctrl+left",
        "cursor_left_word",
        "cursor left word",
        show=False,
    ),
    Binding(
        "right", "cursor_right", "cursor right", show=False
    ),
    Binding(
        "ctrl+right",
        "cursor_right_word",
        "cursor right word",
        show=False,
    ),
    Binding(
        "backspace",
        "delete_left",
        "delete left",
        show=False,
    ),
    Binding("home,ctrl+a", "home", "home", show=False),
    Binding("end,ctrl+e", "end", "end", show=False),
    Binding(
        "delete,ctrl+d",
        "delete_right",
        "delete 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,
    ),
]
Key(s) Description
left Move the cursor left.
ctrl+left Move the cursor one word to the left.
right Move the cursor right or accept the completion suggestion.
ctrl+right Move the cursor one word to the right.
backspace Delete the character to the left of the cursor.
home,ctrl+a Go to the beginning of the input.
end,ctrl+e Go to the end of the input.
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.

COMPONENT_CLASSES class-attribute

COMPONENT_CLASSES: set[str] = {
    "input--cursor",
    "input--placeholder",
    "input--suggestion",
}
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).

cursor_width property

cursor_width: int

The width of the input (with extra space for cursor at the end).

suggester instance-attribute

suggester: Suggester | None = suggester

The suggester used to provide completions as the user types.

validate_on instance-attribute

validate_on = (
    set(validate_on) & _POSSIBLE_VALIDATE_ON_VALUES
    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"])

Changed class

Bases: Message

Posted when the value changes.

Can be handled using on_input_changed in a subclass of Input or in a parent widget in the DOM.

control property

control: Input

Alias for self.input.

input instance-attribute

input: Input

The Input widget that was changed.

validation_result class-attribute instance-attribute

validation_result: ValidationResult | None = None

The result of validating the value (formed by combining the results from each validator), or None if validation was not performed (for example when no validators are specified in the Inputs init)

value instance-attribute

value: str

The value that the input was changed to.

Submitted class

Bases: Message

Posted when the enter key is pressed within an Input.

Can be handled using on_input_submitted in a subclass of Input or in a parent widget in the DOM.

control property

control: Input

Alias for self.input.

input instance-attribute

input: Input

The Input widget that is being submitted.

validation_result class-attribute instance-attribute

validation_result: ValidationResult | None = None

The result of validating the value on submission, formed by combining the results for each validator. This value will be None if no validation was performed, which will be the case if no validators are supplied to the corresponding Input widget.

value instance-attribute

value: str

The value of the Input being submitted.

action_cursor_left method

def action_cursor_left(self):

Move the cursor one position to the left.

action_cursor_left_word method

def action_cursor_left_word(self):

Move the cursor left to the start of a word.

action_cursor_right method

def action_cursor_right(self):

Accept an auto-completion or move the cursor one position to the right.

action_cursor_right_word method

def action_cursor_right_word(self):

Move the cursor right to the start of a word.

action_delete_left method

def action_delete_left(self):

Delete one character to the left of the current cursor position.

action_delete_left_all method

def action_delete_left_all(self):

Delete all characters to the left of the cursor position.

action_delete_left_word method

def action_delete_left_word(self):

Delete leftward of the cursor position to the start of a word.

action_delete_right method

def action_delete_right(self):

Delete one character at the current cursor position.

action_delete_right_all method

def action_delete_right_all(self):

Delete the current character and all characters to the right of the cursor position.

action_delete_right_word method

def action_delete_right_word(self):

Delete the current character and all rightward to the start of the next word.

action_end method

def action_end(self):

Move the cursor to the end of the input.

action_home method

def action_home(self):

Move the cursor to the start of the input.

action_submit async

def action_submit(self):

Handle a submit action.

Normally triggered by the user pressing Enter. This may also run any validators.

clear method

def clear(self):

Clear the input.

insert_text_at_cursor method

def insert_text_at_cursor(self, text):

Insert new text at the cursor, move the cursor to the end of the new text.

Parameters
Name Type Description Default
text str

New text to insert.

required

validate method

def validate(self, value):

Run all the validators associated with this Input on the supplied value.

Runs all validators, combines the result into one. If any of the validators failed, the combined result will be a failure. If no validators are present, None will be returned. This also sets the -invalid CSS class on the Input if the validation fails, and sets the -valid CSS class on the Input if the validation succeeds.

Returns
Type Description
ValidationResult | None

A ValidationResult indicating whether all validators succeeded or not. That is, if any validator fails, the result will be an unsuccessful validation.