Input Components¶
Input components capture user data. They all accept a ReactiveVar for their
value / checked parameter so they stay in sync with state automatically.
Button¶
A clickable button. The most fundamental interactive component.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str | callable |
— | Button text; can be a lambda for reactive labels |
on_click |
Callable | None |
None |
Called (no arguments) when clicked; may be async |
variant |
str |
"primary" |
Visual style: "primary" | "secondary" | "ghost" | "danger" |
disabled |
bool | ReactiveVar[bool] |
False |
Disables interaction when True |
icon |
str |
"" |
Icon name or emoji shown before the label |
Variants
primary— solid accent colour (default)secondary— outlined/muted styleghost— transparent background, subtle hoverdanger— red/destructive action
Example
ui.Button("Save", on_click=save_data)
ui.Button("Delete", variant="danger", on_click=delete_item)
ui.Button("Cancel", variant="ghost", on_click=lambda: modal_open.set(False))
ui.Button("Export CSV", variant="secondary", icon="📥")
# Async handler — works natively
async def handle_submit():
await session.set_theme("dark")
result.set(await fetch_data())
ui.Button("Fetch data", on_click=handle_submit)
# Reactive disabled state
is_loading = ui.state(False)
ui.Button("Submit", disabled=is_loading, on_click=lambda: is_loading.set(True))
TextInput¶
A single-line text field with optional label, error, and help text.
Signature
TextInput(*, label="", placeholder="", value=None, on_change=None,
disabled=False, error="", help_text="")
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Field label shown above the input |
placeholder |
str |
"" |
Placeholder text when empty |
value |
ReactiveVar[str] | str | None |
None |
Controlled value |
on_change |
Callable[[str], None] | None |
None |
Called with the new string on every keystroke |
disabled |
bool |
False |
Disables the field |
error |
str | ReactiveVar[str] |
"" |
Error message shown below the field in red |
help_text |
str |
"" |
Help text shown below the field |
Example
name = ui.state("")
name_error = ui.state("")
def validate(v):
name.set(v)
name_error.set("" if v.strip() else "Name is required")
ui.TextInput(
label="Full name",
placeholder="Jane Smith",
value=name,
on_change=validate,
error=name_error,
help_text="Enter your legal name as it appears on your ID",
)
NumberInput¶
A numeric input with optional min/max bounds and step.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Field label |
value |
ReactiveVar[float] | float | None |
None |
Controlled value |
on_change |
Callable[[float], None] | None |
None |
Called with the new number |
min |
float | None |
None |
Minimum allowed value |
max |
float | None |
None |
Maximum allowed value |
step |
float |
1 |
Increment/decrement step |
disabled |
bool |
False |
Disables the field |
Example
quantity = ui.state(1)
ui.NumberInput(
label="Quantity",
value=quantity,
on_change=quantity.set,
min=1,
max=100,
step=1,
)
Textarea¶
A multi-line text field.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Field label |
placeholder |
str |
"" |
Placeholder text |
value |
ReactiveVar[str] | str | None |
None |
Controlled value |
on_change |
Callable[[str], None] | None |
None |
Called on change |
rows |
int |
4 |
Initial visible row count |
disabled |
bool |
False |
Disables the field |
Example
notes = ui.state("")
ui.Textarea(
label="Notes",
placeholder="Add any additional comments…",
value=notes,
on_change=notes.set,
rows=6,
)
ui.Text(lambda: f"{len(notes.value)} characters")
Select¶
A dropdown selector.
Signature
Select(*, label="", options=[], value=None, on_change=None,
placeholder="Select...", disabled=False)
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Field label |
options |
list[str] | list[dict] |
[] |
Items to show; dicts need "label" and "value" keys |
value |
ReactiveVar[str] | str | None |
None |
Currently selected value |
on_change |
Callable[[str], None] | None |
None |
Called with the new selected value |
placeholder |
str |
"Select..." |
Placeholder shown when nothing is selected |
disabled |
bool |
False |
Disables the dropdown |
Example
period = ui.state("30d")
ui.Select(
label="Time period",
options=["7d", "30d", "90d", "1y"],
value=period,
on_change=period.set,
)
# With label/value dicts
ui.Select(
label="Country",
options=[
{"label": "United States", "value": "US"},
{"label": "United Kingdom", "value": "GB"},
{"label": "Germany", "value": "DE"},
],
value=country,
on_change=country.set,
)
Checkbox¶
A boolean checkbox with a label.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Text shown next to the checkbox |
checked |
ReactiveVar[bool] | bool | None |
None |
Controlled checked state |
on_change |
Callable[[bool], None] | None |
None |
Called with the new boolean |
disabled |
bool |
False |
Disables interaction |
Example
agree = ui.state(False)
ui.Checkbox(
label="I agree to the terms and conditions",
checked=agree,
on_change=agree.set,
)
ui.Button("Continue", disabled=lambda: not agree.value)
Switch¶
A toggle switch. Semantically identical to Checkbox but rendered as a pill toggle.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Text shown next to the switch |
checked |
ReactiveVar[bool] | bool | None |
None |
Controlled checked state |
on_change |
Callable[[bool], None] | None |
None |
Called with the new boolean; may be async |
disabled |
bool |
False |
Disables interaction |
Example
dark_mode = ui.state(False)
async def toggle(v):
dark_mode.set(v)
await session.set_theme("dark" if v else "light")
ui.Switch(label="Dark mode", checked=dark_mode, on_change=toggle)
Slider¶
A range slider for numeric input.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Label shown above the slider |
value |
ReactiveVar[float] | float | None |
None |
Controlled value |
on_change |
Callable[[float], None] | None |
None |
Called as the user drags |
min |
float |
0 |
Minimum value |
max |
float |
100 |
Maximum value |
step |
float |
1 |
Step increment |
Example
volume = ui.state(50)
ui.Slider(label="Volume", value=volume, on_change=volume.set, min=0, max=100)
ui.Text(lambda: f"Volume: {int(volume.value)}%")
RadioGroup¶
A group of mutually exclusive radio buttons.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Group label shown above the options |
options |
list[str] | list[dict] |
[] |
Radio options (same format as Select) |
value |
ReactiveVar[str] | str | None |
None |
Currently selected value |
on_change |
Callable[[str], None] | None |
None |
Called when selection changes |
Example
plan = ui.state("starter")
ui.RadioGroup(
label="Pricing plan",
options=["starter", "pro", "enterprise"],
value=plan,
on_change=plan.set,
)
ui.Text(lambda: f"Selected: {plan.value}")
FileUpload¶
A file picker that uploads files to the server and returns paths.
Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
prompt |
str |
"" |
Text shown on the drop zone / button |
accept |
str |
"" |
MIME type or extension filter, e.g. "image/*" or ".csv" |
multiple |
bool |
False |
Allow multiple files |
on_change |
Callable[[list[str]], None] | None |
None |
Called with a list of server-side paths after upload |
Example
uploaded_paths = ui.state([])
def handle_upload(paths):
uploaded_paths.set(paths)
ui.FileUpload(
prompt="Drop a CSV file here or click to browse",
accept=".csv",
on_change=handle_upload,
)
ui.Text(lambda: f"Uploaded: {', '.join(uploaded_paths.value)}" if uploaded_paths.value else "No file yet")
Accessing uploaded files
Files are saved to a per-session temporary directory. The paths returned to on_change
are absolute paths on the server filesystem. Use pathlib.Path(path).read_bytes() or
pandas.read_csv(path) to process them.