Select datatable row using text input with selection

hi there,

I try to use a text input to filter a data table using python. Using the example below it works well if you don’t select anything. However, if you select a row, I have to also update the select indices. This works also well but I keep loosing focus on my text input box whenever the datatable change with a selection, which make the entier tool unusable.

Any idea ? If possible I would like to not write JS code.
Thanks !

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import TextInput, DataTable, TableColumn
import pandas as pd

class SelectableDataTable() :

	def __init__(self, df, select_column) :
		self.df = df
		self.sdf = df
		self.source = ColumnDataSource(df)

		self.select_column = select_column

		self.ti = TextInput()
		self.ti.on_change("value_input", self.input_callback)

		columns = [TableColumn(field=column, title=column) for column in df.columns]
		self.dt = DataTable(source=self.source, columns=columns, selectable="checkbox")

		self.source.selected.on_change("indices", self.source_selection_change)
		self.save_selection = True
		self.selected = set()

	def input_callback(self, attr, old, new) :
		self.sdf = df[df[self.select_column].str.contains(new)]
		self.source.data = self.sdf

		sdf_idxs = list(self.sdf.index)
		select_idx = [idx for idx, sdf_idx in enumerate(sdf_idxs) if sdf_idx in self.selected]

		self.save_selection = False
		self.source.selected.indices = select_idx
		self.save_selection = True

	def source_selection_change(self, attr, old, new) :
		if not self.save_selection : return
		sdf_idxs = list(self.sdf.index)
		selected = {sdf_idxs[index] for index in new}
		unselected = set(sdf_idxs) - selected
		self.selected = (self.selected | selected) - unselected

df = pd.DataFrame({'numbers': list(range(10)), 'colors': ["red", "blue"] * 5}, columns=['numbers', 'colors'])
sdt = SelectableDataTable(df, "colors")

layout = column(sdt.ti, sdt.dt)
curdoc().add_root(layout)

Edit : fix a small bug

I don’t think it’s possible without JS. Bokeh uses SlickGrid for its tables, and it adds some focusable divs before and after the main table body - I think, for paste functionality. Alas, it’s not configurable.
With that being said, Bokeh uses its own fork of SlickGrid. So if you think that this functionality should be there, you’re welcome to create a feature request.