or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-app.mddata-structures.mderrors-edge-cases.mdindex.mdpatterns-recipes.mdprompts-api.mdquick-reference.mdwidgets-api.md
tile.json

prompts-api.mddocs/

Prompts API

All high-level prompt functions from inquirer_textual.prompts module. These are the simplest way to collect single inputs.

Note on API Design: The high-level prompts.* functions provide a simplified API for common use cases. Some parameters available in the underlying widget classes (like default for InquirerText or mandatory for widgets) are intentionally not exposed to keep the API simple. For access to all widget parameters, use the widget classes directly with InquirerApp.prompt() (see Widgets API and InquirerApp Advanced).

Import

from typing import Iterable
from inquirer_textual import prompts
from inquirer_textual.common.Choice import Choice
from inquirer_textual.common.Shortcut import Shortcut
from textual.validation import Validator, Function

prompts.text()

Text input prompt with optional validation.

def text(
    message: str,
    shortcuts: list[Shortcut] | None = None,
    validators: Validator | Iterable[Validator] | None = None
) -> Result[str]

Parameters

  • message (str): Prompt message displayed to user
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts for custom commands
  • validators (Validator | Iterable[Validator] | None): Textual validators for input validation

Returns

Result[str] with:

  • command: 'select' (Enter), 'quit' (Ctrl+D), or custom shortcut command
  • value: Input text string

Behavior

  • If validation fails on Enter, prompt remains active and shows error
  • Validation runs on each keystroke and on submit
  • Empty input is allowed unless validators prevent it

Examples

Basic text input:

result = prompts.text("Enter your name:")
if result.command == 'select':
    print(f"Hello, {result.value}!")

With validation:

from textual.validation import Function

result = prompts.text(
    "Enter email:",
    validators=Function(lambda s: '@' in s and '.' in s, "Invalid email format")
)
if result.command == 'select':
    email = result.value

Multiple validators:

from textual.validation import Validator, ValidationResult

class MinLength(Validator):
    def __init__(self, length: int):
        super().__init__()
        self.length = length
    def validate(self, value: str) -> ValidationResult:
        return self.success() if len(value) >= self.length else self.failure(f"Min {self.length} chars")

class NoSpaces(Validator):
    def validate(self, value: str) -> ValidationResult:
        return self.success() if ' ' not in value else self.failure("No spaces allowed")

result = prompts.text(
    "Username:",
    validators=[MinLength(3), NoSpaces()]
)

With shortcuts:

shortcuts = [
    Shortcut('escape', 'cancel', 'Cancel'),
    Shortcut('ctrl+s', 'save_draft', 'Save Draft')
]

result = prompts.text("Enter text:", shortcuts=shortcuts)

if result.command == 'cancel':
    print("User cancelled")
elif result.command == 'save_draft':
    save_draft(result.value)
elif result.command == 'select':
    save_final(result.value)

prompts.secret()

Password/secret input with masked display.

def secret(
    message: str,
    shortcuts: list[Shortcut] | None = None
) -> Result[str]

Parameters

  • message (str): Prompt message displayed to user
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts

Returns

Result[str] with:

  • command: 'select', 'quit', or custom shortcut command
  • value: Secret string (actual value, not masked)

Behavior

  • Input is masked with bullets (•) during typing
  • Result.value contains the actual unmasked string
  • No built-in validation support (use custom checks after)

Examples

result = prompts.secret("Enter password:")
if result.command == 'select':
    password = result.value
    if len(password) < 8:
        print("Password too short")
    else:
        authenticate(password)
result = prompts.secret("API key:", shortcuts=[Shortcut('escape', 'cancel')])
if result.command == 'select':
    api_key = result.value
elif result.command == 'cancel':
    print("Cancelled")

prompts.number()

Integer number input prompt.

def number(
    message: str,
    shortcuts: list[Shortcut] | None = None
) -> Result[str]

Parameters

  • message (str): Prompt message displayed to user
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts

Returns

Result[str] with:

  • command: 'select', 'quit', or custom shortcut command
  • value: Numeric STRING validated as integer

Behavior

  • Only allows integer characters (digits, minus sign at start)
  • Result.value is a string, not int
  • Convert to int with: int(result.value)
  • Empty input prevents submission

Examples

result = prompts.number("Enter your age:")
if result.command == 'select':
    age = int(result.value)  # Convert to int
    print(f"Age: {age}")
result = prompts.number("Port number:")
if result.command == 'select':
    port = int(result.value)
    if 1024 <= port <= 65535:
        start_server(port)
    else:
        print("Port must be 1024-65535")

prompts.confirm()

Yes/No confirmation prompt.

def confirm(
    message: str,
    shortcuts: list[Shortcut] | None = None,
    default: bool = False,
    mandatory: bool = True
) -> Result[bool]

Parameters

  • message (str): Prompt message displayed to user
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts
  • default (bool): Default value; affects display: True shows (Y/n), False shows (y/N)
  • mandatory (bool): If False, allows Ctrl+C to exit without response

Returns

Result[bool] with:

  • command: 'select', 'quit', 'ctrl+c' (if not mandatory), or custom shortcut command
  • value: Boolean value, or None if Ctrl+C pressed (when mandatory=False)

Behavior

  • Press 'y' for Yes (True), 'n' for No (False)
  • Default value affects capitalization in prompt display
  • If mandatory=False and user presses Ctrl+C: command='ctrl+c', value=None

Examples

Basic confirmation:

result = prompts.confirm("Continue with installation?", default=True)
if result.command == 'select':
    if result.value:
        install()
    else:
        print("Installation cancelled")

Non-mandatory:

result = prompts.confirm("Delete file?", default=False, mandatory=False)
if result.command == 'select':
    if result.value:
        delete_file()
elif result.command == 'ctrl+c':
    print("User aborted")

With shortcuts:

result = prompts.confirm(
    "Overwrite existing?",
    default=False,
    shortcuts=[Shortcut('a', 'all', 'Yes to All')]
)
if result.command == 'all':
    overwrite_all()
elif result.command == 'select' and result.value:
    overwrite_one()

prompts.select()

Single selection from a list.

def select(
    message: str,
    choices: list[str | Choice],
    shortcuts: list[Shortcut] | None = None,
    default: str | Choice | None = None,
    mandatory: bool = True
) -> Result[str | Choice]

Parameters

  • message (str): Prompt message displayed to user
  • choices (list[str | Choice]): List of string choices or Choice objects
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts
  • default (str | Choice | None): Initial highlighted selection
  • mandatory (bool): If False, allows Ctrl+C to exit without selection

Returns

Result[str | Choice] with:

  • command: 'select', 'quit', 'ctrl+c' (if not mandatory), Choice.command, or custom shortcut command
  • value: Selected string or Choice object, or None if Ctrl+C (when mandatory=False)

Behavior

  • Up/Down arrows navigate list
  • Enter confirms selection
  • If Choice has custom command, Result.command will be that command
  • default parameter sets initial highlight position

Examples

String choices:

result = prompts.select(
    "Select language:",
    ["Python", "JavaScript", "Go", "Rust"]
)
if result.command == 'select':
    language = result.value  # str
    print(f"Selected: {language}")

With default:

result = prompts.select(
    "Log level:",
    ["DEBUG", "INFO", "WARNING", "ERROR"],
    default="INFO"
)

Choice objects with data:

from inquirer_textual.common.Choice import Choice

environments = [
    Choice("Development", data={"url": "localhost:3000", "debug": True}),
    Choice("Staging", data={"url": "staging.example.com", "debug": False}),
    Choice("Production", data={"url": "example.com", "debug": False})
]

result = prompts.select("Select environment:", environments)
if result.command == 'select':
    env = result.value
    print(f"Connecting to {env.data['url']}")
    if env.data['debug']:
        enable_debug()

Choice with custom commands:

from inquirer_textual.common.Choice import Choice

actions = [
    Choice("View Details", command="view"),
    Choice("Edit", command="edit"),
    Choice("Delete", command="delete")
]

result = prompts.select("Select action:", actions)

if result.command == 'view':
    show_details()
elif result.command == 'edit':
    edit_item()
elif result.command == 'delete':
    delete_item()

Non-mandatory:

result = prompts.select("Choose:", ["A", "B", "C"], mandatory=False)
if result.command == 'select':
    process(result.value)
elif result.command == 'ctrl+c':
    print("No selection made")

prompts.checkbox()

Multiple selection from a list with checkboxes.

def checkbox(
    message: str,
    choices: list[str | Choice],
    shortcuts: list[Shortcut] | None = None,
    enabled: list[str | Choice] | None = None
) -> Result[list[str | Choice]]

Parameters

  • message (str): Prompt message displayed to user
  • choices (list[str | Choice]): List of string choices or Choice objects
  • shortcuts (list[Shortcut] | None): Optional keyboard shortcuts
  • enabled (list[str | Choice] | None): Pre-checked items (NOT FUNCTIONAL in v0.2.0)

Returns

Result[list[str | Choice]] with:

  • command: 'select', 'quit', or custom shortcut command
  • value: List of checked strings or Choice objects (empty list if none checked)

Behavior

  • Up/Down arrows navigate list
  • Space toggles checkbox on current item
  • Enter confirms selection and returns all checked items
  • Known bug: enabled parameter does NOT work; all items start unchecked

Examples

String choices:

features = ["Authentication", "Database", "Caching", "Logging"]
result = prompts.checkbox("Select features to enable:", features)
if result.command == 'select':
    enabled_features = result.value  # list[str]
    print(f"Enabled: {', '.join(enabled_features)}")

Choice objects:

from inquirer_textual.common.Choice import Choice

plugins = [
    Choice("ESLint", data={"package": "eslint"}),
    Choice("Prettier", data={"package": "prettier"}),
    Choice("Jest", data={"package": "jest"})
]

result = prompts.checkbox("Select plugins:", plugins)
if result.command == 'select':
    for plugin in result.value:
        install_package(plugin.data["package"])

With shortcuts:

shortcuts = [
    Shortcut('a', 'all', 'Select All'),
    Shortcut('n', 'none', 'Select None')
]

result = prompts.checkbox("Select items:", ["A", "B", "C"], shortcuts=shortcuts)

if result.command == 'all':
    # Custom logic for "select all"
    selected = ["A", "B", "C"]
elif result.command == 'none':
    selected = []
elif result.command == 'select':
    selected = result.value

Enabled parameter (NOT WORKING in v0.2.0):

# This does NOT work in v0.2.0
result = prompts.checkbox(
    "Select:",
    ["A", "B", "C"],
    enabled=["A", "B"]  # Has no effect; all items start unchecked
)
# Workaround: User must manually check items with Space

prompts.multi()

Sequential multi-prompt form.

def multi(
    widgets: list[InquirerWidget],
    shortcuts: list[Shortcut] | None = None
) -> Result[list[Any]]

Parameters

  • widgets (list[InquirerWidget]): List of widget instances to display sequentially
  • shortcuts (list[Shortcut] | None): Keyboard shortcuts available throughout flow

Returns

Result[list[Any]] with:

  • command: 'select' (all completed), 'quit' (Ctrl+D), or custom shortcut command
  • value: List of values from all widgets in order

Behavior

  • Displays widgets one at a time in sequence
  • After user completes one widget, next widget appears
  • If user quits early (Ctrl+D or shortcut), returns values completed so far
  • Each widget maintains its own validation

Examples

Basic form:

from inquirer_textual.widgets.InquirerText import InquirerText
from inquirer_textual.widgets.InquirerConfirm import InquirerConfirm

widgets = [
    InquirerText("Name:"),
    InquirerText("Email:"),
    InquirerConfirm("Subscribe?", default=True)
]

result = prompts.multi(widgets)
if result.command == 'select':
    name, email, subscribe = result.value
    print(f"Name: {name}, Email: {email}, Subscribe: {subscribe}")

Registration form:

from inquirer_textual.widgets.InquirerText import InquirerText
from inquirer_textual.widgets.InquirerSecret import InquirerSecret
from inquirer_textual.widgets.InquirerNumber import InquirerNumber
from textual.validation import Function

widgets = [
    InquirerText(
        "Username:",
        validators=Function(lambda s: len(s) >= 3, "Min 3 characters")
    ),
    InquirerSecret("Password:"),
    InquirerText(
        "Email:",
        validators=Function(lambda s: '@' in s, "Invalid email")
    ),
    InquirerNumber("Age:")
]

result = prompts.multi(widgets)
if result.command == 'select':
    username, password, email, age_str = result.value
    age = int(age_str)
    create_user(username, password, email, age)

Configuration wizard:

from inquirer_textual.widgets.InquirerText import InquirerText
from inquirer_textual.widgets.InquirerSelect import InquirerSelect
from inquirer_textual.widgets.InquirerCheckbox import InquirerCheckbox

widgets = [
    InquirerText("Project name:"),
    InquirerSelect("Framework:", ["React", "Vue", "Angular"]),
    InquirerCheckbox("Features:", ["TypeScript", "ESLint", "Tests"]),
    InquirerSelect("Package manager:", ["npm", "yarn", "pnpm"])
]

result = prompts.multi(widgets)
if result.command == 'select':
    name, framework, features, pkg_manager = result.value
    create_project(name, framework, features, pkg_manager)

With shortcuts and early exit:

shortcuts = [
    Shortcut('escape', 'cancel', 'Cancel'),
    Shortcut('ctrl+s', 'save_draft', 'Save Draft')
]

widgets = [
    InquirerText("Title:"),
    InquirerText("Description:"),
    InquirerText("Tags:")
]

result = prompts.multi(widgets, shortcuts=shortcuts)

if result.command == 'cancel':
    print("Cancelled")
elif result.command == 'save_draft':
    # Partial data - some fields may not be filled
    save_draft(result.value)
elif result.command == 'select':
    # All fields completed
    title, description, tags = result.value
    create_post(title, description, tags)

Handling early quit:

widgets = [
    InquirerText("Field 1:"),
    InquirerText("Field 2:"),
    InquirerText("Field 3:")
]

result = prompts.multi(widgets)

if result.command == 'quit':
    # User quit early
    completed_count = len(result.value)
    print(f"Completed {completed_count} of {len(widgets)} fields")
    if completed_count >= 2:
        # Process partial data
        process_partial(result.value)
elif result.command == 'select':
    # All fields completed
    f1, f2, f3 = result.value
    process_complete(f1, f2, f3)

Common Patterns

Always Check Command

result = prompts.text("Input:")
# ALWAYS check command before using value
if result.command == 'select':
    # Safe to use result.value
    process(result.value)
elif result.command == 'quit':
    print("User quit")

Reusable Shortcuts

COMMON_SHORTCUTS = [
    Shortcut('escape', 'cancel', 'Cancel'),
    Shortcut('ctrl+h', 'help', 'Help')
]

result1 = prompts.text("Input 1:", shortcuts=COMMON_SHORTCUTS)
result2 = prompts.text("Input 2:", shortcuts=COMMON_SHORTCUTS)

Choice Data Pattern

from inquirer_textual.common.Choice import Choice

def create_choices(items):
    return [
        Choice(item['name'], data=item)
        for item in items
    ]

items = [{'name': 'A', 'id': 1}, {'name': 'B', 'id': 2}]
choices = create_choices(items)

result = prompts.select("Pick:", choices)
if result.command == 'select':
    item_id = result.value.data['id']

Validation Helper

from textual.validation import Validator, ValidationResult

def create_min_length_validator(min_len: int) -> Validator:
    class MinLengthValidator(Validator):
        def validate(self, value: str) -> ValidationResult:
            if len(value) >= min_len:
                return self.success()
            return self.failure(f"Minimum {min_len} characters required")
    return MinLengthValidator()

result = prompts.text("Username:", validators=create_min_length_validator(3))