express.ui.input_task_button

express.ui.input_task_button(
    id,
    label,
    *args,
    icon=None,
    label_busy='Processing...',
    icon_busy=MISSING,
    width=None,
    type='primary',
    auto_reset=True,
    **kwargs,
)

Creates a button for launching longer-running operations.

Its value is initially zero, and increments by one each time it is pressed. It is similar to input_action_button, except it prevents the user from clicking when its operation is already in progress.

Upon click, it automatically displays a customizable progress message and disables itself; and after the server has dealt with whatever reactivity is triggered from the click, the button automatically resets to its original appearance and re-enables itself.

In some advanced use cases, it may be necessary to keep a task button in its busy state even after the normal reactive processing has completed. Calling :func:~shiny.express.ui.update_task_button(id, state = "busy") from the server will opt out of any currently pending reset for a specific task button. After doing so, the button can be re-enabled by calling update_task_button(id, state = "ready") after each click's work is complete.

You can also pass an explicit auto_reset = FALSE to input_task_button(), which means that button will never be automatically re-enabled and will require update_task_button(id, state = "ready") to be called each time.

Note that, as a general rule, Shiny's update family of functions do not take effect at the instant that they are called, but are held until the end of the current reactive cycle. So if you have many different reactive calculations and outputs, you don't have to be too careful about when you call update_task_button(id, state = "ready"), as the button on the client will not actually re-enable until the same moment that all of the updated outputs simultaneously sent to the client.

Parameters

id : str

An input id.

label : TagChild

A button label.

*args : TagChild = ()

[Experimental] Can be used to add additional states besides “ready” and “busy”. Pass a span with slot="state_name" for each new state, and call update_task_button with state="state_name" to switch the button to that state.

icon : TagChild = None

An icon to appear inline with the button/link.

label_busy : TagChild = 'Processing…'

A label to appear when the button is busy.

icon_busy : TagChild | MISSING_TYPE = MISSING

An icon to appear inline with the button/link when the button is busy.

width : Optional[str] = None

The CSS width, e.g. ‘400px’, or ‘100%’

type : Optional[str] = 'primary'

One of the Bootstrap theme colors (‘primary’, ‘default’, ‘secondary’, ‘success’, ‘danger’, ‘warning’, ‘info’, ‘light’, ‘dark’), or None to leave off the Bootstrap-specific button CSS classes. Defaults to ‘primary’.

auto_reset : bool = True

Whether to automatically reset the button to “ready” after the task completes. If False, the button will remain in the “busy” state until update_task_button is called with state="ready". Also note that even if auto_reset=True, calling update_task_button with state="busy" will prevent the button from automatically resetting.

****kwargs** : TagAttrValue = {}

Attributes to be applied to the button.

Returns

: Tag

A UI element

Notes

Server value

An integer representing the number of clicks.

See Also

Examples

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400

## file: app.py
import asyncio
from datetime import datetime

from shiny import reactive, render
from shiny.express import input, ui

ui.h5("Current time")


@render.text
def current_time():
    reactive.invalidate_later(1)
    return datetime.now().strftime("%H:%M:%S")


with ui.p():
    "Notice that the time above updates every second, even if you click the button below."


@ui.bind_task_button(button_id="btn")
@reactive.extended_task
async def slow_compute(a: int, b: int) -> int:
    await asyncio.sleep(3)
    return a + b


with ui.layout_sidebar():
    with ui.sidebar():
        ui.input_numeric("x", "x", 1)
        ui.input_numeric("y", "y", 2)
        ui.input_task_button("btn", "Compute, slowly")
        ui.input_action_button("btn_cancel", "Cancel")

    @reactive.effect
    @reactive.event(input.btn, ignore_none=False)
    def handle_click():
        # slow_compute.cancel()
        slow_compute(input.x(), input.y())

    @reactive.effect
    @reactive.event(input.btn_cancel)
    def handle_cancel():
        slow_compute.cancel()

    ui.h5("Sum of x and y")

    @render.text
    def show_result():
        return str(slow_compute.result())