Skip to content

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

Button(label, *, on_click=None, variant="primary", disabled=False, icon="")

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 style
  • ghost — transparent background, subtle hover
  • danger — 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

NumberInput(*, label="", value=None, on_change=None, min=None, max=None,
            step=1, disabled=False)

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

Textarea(*, label="", placeholder="", value=None, on_change=None,
         rows=4, disabled=False)

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

Checkbox(*, label="", checked=None, on_change=None, disabled=False)

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

Switch(*, label="", checked=None, on_change=None, disabled=False)

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

Slider(*, label="", value=None, on_change=None, min=0, max=100, step=1)

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

RadioGroup(*, label="", options=[], value=None, on_change=None)

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

FileUpload(prompt="", *, accept="", multiple=False, on_change=None)

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.