gr.Textbox — the input that carries almost every demo

Every demo starts as a string — gr.Textbox is where it lands.

Textbox has been in gradio since the first PyPI release in Feb 2019 — and the original component fit in nine lines of code.

What it does

gr.Textbox renders a text input that works as single-line field, multi-line textarea, masked password, or output pane — one component, four jobs. In gradio 6.18.0 its constructor takes 29 parameters: type ("text" | "password" | "email"), lines/max_lines for textarea height, placeholder, label, info, max_length for browser-enforced caps, submit_btn/stop_btn to build a chat-style input with no extra Button, and html_attributes for raw HTML attributes like spellcheck. Your function always receives a plain str — or None when the box is empty.

Why it matters

Almost every ML demo consumes text: prompts, reviews, queries, API keys. Textbox is the lowest-friction way to get one from a user, and it doubles as the standard output component for generated text. It also carries the richest event set of any input component — change, input, submit, focus, blur, select, copy, stop — so the same widget can power a click-to-run form (submit), a live-updating dashboard (input), or a press-Enter chat box (submit_btn=True). Master this one component and half of gr.Blocks is already familiar.

Examples

import gradio as gr

def greet(name):
    return f"Hello, {name}!"

demo = gr.Interface(
    fn=greet,
    inputs=gr.Textbox(label="Your name", placeholder="Ada Lovelace"),
    outputs=gr.Textbox(label="Greeting"),
)
demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7861
* To create a public link, set `share=True` in `launch()`.

Rendered UI (verified via the app's /config payload): a gr.Interface layout — inputs on the left with a single-line Textbox labeled "Your name" showing the placeholder "Ada Lovelace", plus auto-generated Clear and Submit buttons; outputs on the right with a Textbox labeled "Greeting" and a Flag button. The greet function is wired to two triggers: click on Submit and submit on the input Textbox, so pressing Enter runs it too. Calling greet("Ada") returns "Hello, Ada!".

gr.Interface wraps everything for you: the Submit button, Enter-to-submit on the Textbox, even the Flag button. Textbox is the input type you'll write most.

import gradio as gr

def count_words(text):
    words = [w for w in text.split() if w]
    return len(words), f"{len(text)} chars"

with gr.Blocks() as demo:
    gr.Markdown("## Live word counter")
    inp = gr.Textbox(lines=3, placeholder="Start typing…", label="Draft")
    words = gr.Number(label="Words", precision=0)
    chars = gr.Textbox(label="Size")
    inp.input(count_words, inputs=inp, outputs=[words, chars])

demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7862
* To create a public link, set `share=True` in `launch()`.

Rendered UI (verified via /config): a "## Live word counter" Markdown header, a 3-line textarea labeled "Draft" with placeholder "Start typing…", a Number labeled "Words", and a single-line Textbox labeled "Size". The config registers exactly one dependency: the Draft Textbox on the input trigger — no Button exists in the component tree. count_words("Gradio makes ML demos trivial") returns (5, '29 chars'), so typing that sentence shows Words=5 and Size="29 chars" on every keystroke.

.input() fires on every keystroke — use it for live previews; .change() waits until the value commits (blur or Enter).

import gradio as gr

def check_key(key):
    if not key:
        return "Enter a key first."
    if key.startswith("sk-") and len(key) >= 20:
        return "Key format looks valid — never print it."
    return "Key should start with 'sk-'."

with gr.Blocks() as demo:
    gr.Markdown("## BYO API key")
    key = gr.Textbox(
        type="password", label="API key", placeholder="sk-…",
        info="Stored only in this browser session", max_length=80,
    )
    out = gr.Textbox(label="Status")
    key.submit(check_key, inputs=key, outputs=out)

demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7863
* To create a public link, set `share=True` in `launch()`.

Rendered UI (verified via /config): a "## BYO API key" Markdown header, a Textbox labeled "API key" with type=password (the field renders masked), placeholder "sk-…", the info line "Stored only in this browser session" under the label, and a Status output Textbox. One dependency: the API-key Textbox's submit event. check_key("sk-abc123def456ghi789") returns "Key format looks valid — never print it."; check_key("hunter2") returns "Key should start with 'sk-'."; check_key("") returns "Enter a key first." — an untouched box arrives as None, not "".

type="password" masks input; max_length enforces the cap in the browser before your code ever sees it. None is what an empty box delivers — handle it first.

Flags

FlagMeaning
type="password"Masks input; email suggests keyboard hints. Added in gradio 3.10 (PR #2653), which also made any other type value raise.
lines / max_linesTextarea height: minimum rows and when to start scrolling; max_lines defaults to max(lines, 20) for text, 1 for password.
placeholderGhost hint shown in the empty field — the example, not the definition.
infoSmaller helper text under the label; perfect for format hints like "one word per line".
submit_btn / stop_btnBuilt-in send (and stop-generating) buttons, added in 5.0-beta.1 (PR #9235); the border drops automatically — chat look for free.
max_lengthBrowser-enforced character cap (textarea maxlength), added in 5.0-beta.0 (PR #9185) — invalid input never reaches Python.
interactive=FalseRenders as static text instead of an editable field — a read-only output pane.

In the wheel from day one

The first PyPI release, gradio 0.1.0 (Feb 19, 2019), shipped exactly four input components: Sketchpad, Webcam, Textbox, ImageUpload — and Textbox was a nine-line class whose _pre_process() was just `return text`. In gradio 2.0.0 (May 2021) it was still two separate classes: inputs.Textbox(InputComponent) and outputs.Textbox(OutputComponent). Gradio 3.0's Blocks API merged input and output into one component that can play either role.

From function to full API

Textbox absorbed what used to require extra widgets: type="password" and "email" arrived in 3.10.0 (PR #2653, which also started raising on unknown types), max_length in 5.0-beta.0, and submit_btn/stop_btn in 5.0-beta.1 — the same PR that gave ChatInterface its built-in send button (PR #9235, thanks @whitphx). The 6.x docstring describes it as "a textarea for user to enter string input or display string output" — one sentence, both jobs.

What actually crosses the queue

Type text, press Enter, and the frontend posts {"data": ["your text"]}; the backend calls preprocess(x) — an identity function for Textbox — runs your fn, then postprocess()es the return value back to a string for the UI. Textbox's preprocess is the identity function, which is why it's the cheapest component in the library and the one every demo defaults to. The password variant changes nothing server-side: masking is purely a browser input type, so the plain str still lands in your handler — never log it.

Fun facts

Pros

Cons

Takeaways