Skip to content

Proxy, events & inline inputs

Proxy: drive the table from Python

The rendered widget is the proxy (no separate id/session like in R). Call methods on it from a reactive context:

tbl.widget.search("ada")
tbl.widget.order(("field", "desc"))     # column name or 1-based index
tbl.widget.page("number", 3)
tbl.widget.select_rows([1, 3])
tbl.widget.clear_search()
tbl.widget.replace_data(new_df)

Mirrors the R dt2_proxy_* verbs: replace_data, draw, reload, order, search, clear_search, page, select_rows.

from shiny import reactive

@reactive.effect
@reactive.event(input.q)
def _():
    tbl.widget.search(input.q())

Events: read table state reactively

The widget exposes event traits; read them with shinywidgets.reactive_read:

from shinywidgets import reactive_read

reactive_read(tbl.widget, "selected_rows")  # [1-based indices]
reactive_read(tbl.widget, "state")          # {reason, order, search, page, selected}
reactive_read(tbl.widget, "row_check")      # {row, value}  (inline checkbox)
reactive_read(tbl.widget, "row_button")     # {row, id}     (inline button)

Why events re-fire

Each event payload carries a monotonic _seq. Traits dedupe by value, so without it a repeated event (re-clicking the same row) would not re-trigger reactive_read. _seq is the anywidget stand-in for Shiny's priority:"event".

Inline row inputs

Render a control per row and receive its events:

opts = (Options(df)
        .col_checkbox("select", value_col="active")  # seeds checked from a column
        .col_button("act", label="Ping"))

dt2(df, options=opts)
  • A checkbox click sets row_check = {row, value}.
  • A button click sets row_button = {row, id}.

row is the 1-based data row index (independent of the visual sort order). See examples/app_proxy_inputs.py.