✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Dynamic options for drop down

@chriddyp Hi again!

just wondering if there is a solution for handling large dropdowns where number of options is too large (i have some 130k items) and loading them all into dropdown is not practical? the typical solution is to wait for user to enter 1- or more characters and then display only those options that match user input.

if dcc.Dropdown component would fire change (or some other) events on user typing in the drop down then i could attach a callback and set options dynamically. but it would appear that change and value only gets fired/changed only when user actually selects an option in the drop down. is that correct?

if yes, then is there a workaround? or plans to upgrade to newer react-virtualized-select/VirtualizedSelect which has async option?

what i am looking for is experience similar to 4th example of this react-virtualized-select demo:
http://bvaughn.github.io/react-virtualized-select/

many thanks!
anton

In https://github.com/plotly/dash-core-components/pull/47 we upgraded to react-virtualized-select which enabled dropdowns to render with tens of thousands of options, even up to 100 thousand. See https://github.com/plotly/dash/issues/103

However, it is not async. The “Dash way” to mimic the async options would be to have some type of callback that updates the options property based off of the value property and make the value property configurable so that it can update on every key-press instead of when selecting a dropdown. I imagine that the challenge would be in re-rendering the dropdown when the options are open with new options gracefully.
This would be a great addition to the component - if anyone would like to take this on or if any company or organization would like to sponsor this feature (https://plot.ly/products/consulting-and-oem), please reach out :slight_smile:

For now, another solution might be to use a text box input (dcc.Input(type='text')) and update a html.Div below the text box with a list of entries on every keypress. Something like:

@app.callback(Output('available-options', 'children'), [Input('text-box', 'value')])
def display_options(value):
    # some function that you write that might query a database or something
    options = get_options(value, number_of_options=10)
    return html.Ul([html.Li(option) for option in options])

In this case, the user would need to type the entire option, they wouldn’t be able to click on an option to preselect as they would in the dcc.Dropdown, but it could be performant for millions of records.

Thanks Chris!

I ended up doing an dcc.Input where user starts typing, with callback that kicks in drop down options filtering after there are 3 characters or more, and a message to the user instructing to either select an item from the drop down or to keep on typing if there are less than 3 characters. this will work for now, but the biggest issue (aside from a bit quirky user experience) is not being able to have multiple outputs from the same inputs. i know it was discussed before and there is a guide on how to share data safely, but as you would imagine,doing this for each letter update is a little too much. perhaps being able to serve multiple outputs would make more sense for this scenario? for now i will explore if i can do some sort of in-memory cache with reliable invalidation

snippets of the code is:

                html.H5('Start typing to search for the item:',id='instruction'),
                html.Div([
                    html.H5('Name:', className='one columns'),
                    dcc.Input(id='item-input',className='two columns'),
                    dcc.Dropdown(
                        options=[],
                        searchable=True,
                        className='six columns',
                        id='item-selector')
                ], className='row')
.....

        self.app.callback(Out('item-selector', 'options'),
            [In('item-input','value')])(self.suggest_item_options)
        self.app.callback(Out('item-selector', 'value'),
                          [In('item-input', 'value')])(self.set_initial_item_choice)
        self.app.callback(Out('instruction', 'children'),
                          [In('item-input', 'value')])(self.update_instruction)
.....

    def update_instruction(self,value):
        if value is None or len(value) < 3:
            return 'Start typing to search for the item:'
        else:
            data = self.filter_big_list(value)
            return 'Found {} matches. Choose item from the list:'.format(len(data.index))

    def set_initial_item_choice(self,value):
        if value is None or len(value) < 3:
            return ''
        else:
            data = self.filter_big_list(value)
            return '' if len(data.index) =0 else data[0]

    def suggest_item_options(self, value):
        if value is None or len(value) < 3:
            return []
        else:
            data = self.filter_big_list(value)
            return [{'label': name, 'value': name} for name in data]

think for now it will do. will share if and when i get to making a more ‘user friendly’ and efficient solution.

thanks!
anton

Also check out the example here: Capture window/tab closing event. It hasn’t made it into the docs yet.

Thank you, very helpful!

Hi there! I was working on a dash app and it would be great if the dropdown options appeared after typing in a few characters. Has any feature evolved from this?

Thank you!

Yes, this has been updated. See the “Dynamic Options in Dropdown” example in the official dropdown documentation.