Yep! You can create a callback that targets the options
property of the dropdown component. The trick is also including the options
as a State
of the callback so we can append the new value to the current values (you can’t add it as an Input
as this will result in a cyclic dependency)
@app.callback(Output('dropdown', 'options'), [Input('input', 'value')], [State('dropdown', 'options')])
def callback(new_value, current_options):
if not new_value:
return current_options
current_options.append({'label': new_value, 'value': new_value})
return current_options
This is not quite as streamlined as the Shiny behaviour you described though, as this is not built into the dropwdown component, just using Dash itself to update the options. So you’ll need to have an Input
component (here with ID ‘input’) for users to put their new value in. Also it just occurs to me know, that you probably don’t want that being triggered by an Input
dependency, as you’ll get a new option for every character someone types. Maybe a click event on a button could be safer:
app.layout = html.Div([
dcc.Dropdown(
id='dropdown',
options=[
{'label': 'a', 'value': 'a'},
{'label': 'b', 'value': 'b'},
{'label': 'c', 'value': 'c'},
],
value='a'
),
dcc.Input(id='input', value=''),
html.Button('Add Option', id='submit'),
])
@app.callback(
Output('dropdown', 'options'),
[],
[State('input', 'value'), State('dropdown', 'options')],
[Event('submit', 'click')]
)
def callback(new_value, current_options):
if not new_value:
return current_options
current_options.append({'label': new_value, 'value': new_value})
return current_options