@@ -58,7 +58,7 @@ def input_selectize(
5858 selected : Optional [str | list [str ]] = None ,
5959 multiple : bool = False ,
6060 width : Optional [str ] = None ,
61- remove_button : Optional [ bool ] = None ,
61+ remove_button : bool = True ,
6262 options : Optional [dict [str , Jsonifiable | JSEval ]] = None ,
6363) -> Tag :
6464 """
@@ -84,9 +84,10 @@ def input_selectize(
8484 width
8585 The CSS width, e.g. '400px', or '100%'
8686 remove_button
87- Whether to add a remove button. This uses the `clear_button` and `remove_button`
88- selectize plugins which can also be supplied as options. By default it will apply a
89- remove button to multiple selections, but not single selections.
87+ Whether to add a remove button. When `True` (the default), both the
88+ 'clear_button' and 'remove_button' plugins are included. If you want just one
89+ plugin, set this to `False` and specify the desired plugin in the `options`
90+ argument (i.e., `options = {"plugins": ["remove_button"]}`).
9091 options
9192 A dictionary of options. See the documentation of selectize.js for possible options.
9293 If you want to pass a JavaScript function, wrap the string in `ui.JS`.
@@ -200,8 +201,8 @@ def input_select(
200201 "Use `input_selectize()` instead of passing `selectize=True`."
201202 )
202203
203- if isinstance (remove_button , MISSING_TYPE ):
204- remove_button = None
204+ if isinstance (remove_button , MISSING_TYPE ) or remove_button is None :
205+ remove_button = True
205206 else :
206207 warn_deprecated (
207208 "`remove_button` parameter of `input_select()` is deprecated. "
@@ -244,7 +245,7 @@ def _input_select_impl(
244245 selectize : bool = False ,
245246 width : Optional [str ] = None ,
246247 size : Optional [str ] = None ,
247- remove_button : Optional [ bool ] = None ,
248+ remove_button : bool = True ,
248249 options : Optional [dict [str , Jsonifiable | JSEval ]] = None ,
249250) -> Tag :
250251 if options is not None and selectize is False :
@@ -261,7 +262,15 @@ def _input_select_impl(
261262 if options is None :
262263 options = {}
263264
264- plugins = _get_default_plugins (remove_button , multiple , choices_ )
265+ # Although 'remove_button' is primarily for multiple=True and 'clear_button' is for
266+ # multiple=False, we include both in either case since:
267+ # 1. When multiple=True, 'clear_button' can be used to clear _all_ selected items.
268+ # 2. When multiple=False, 'remove_button' is effectively a no-op.
269+ # 3. By including both, we can simplify the client-side logic needed to retain
270+ # these plugins across update_selectize(options=...) calls
271+ default_plugins = None
272+ if remove_button or remove_button is None :
273+ default_plugins = json .dumps (["remove_button" , "clear_button" ])
265274
266275 choices_tags = _render_choices (choices_ , selected )
267276
@@ -283,7 +292,7 @@ def _input_select_impl(
283292 # Which option values should be interpreted as JS?
284293 data_eval = json .dumps (extract_js_keys (options )),
285294 # Supply and retain these plugins across updates (on the client)
286- data_default_plugins = json . dumps ( plugins ) ,
295+ data_default_plugins = default_plugins ,
287296 ),
288297 selectize_deps () if selectize else None ,
289298 ),
@@ -292,26 +301,6 @@ def _input_select_impl(
292301 )
293302
294303
295- def _get_default_plugins (
296- remove_button : bool | None ,
297- multiple : bool ,
298- choices_ : _SelectChoices ,
299- ) -> tuple [str , ...]:
300- if remove_button :
301- # remove_button: remove _each_ item when multiple=True
302- # clear_button: clear _all_ items when multiple=True
303- return ("remove_button" , "clear_button" )
304-
305- if remove_button is None :
306- if multiple :
307- return ("remove_button" , "clear_button" )
308- if "" in choices_ :
309- # Only show clear button if there is an empty choice
310- return ("clear_button" ,)
311-
312- return ()
313-
314-
315304def _normalize_choices (x : SelectChoicesArg ) -> _SelectChoices :
316305 if x is None :
317306 raise TypeError ("`choices` must be a list, tuple, or dict." )
0 commit comments