Dynamic selectbox opitions based on the input of text_input

Hello everybody,

I was wondering whether is there any way to show a dynamic st.selectbox list based on the input of a object obtained previously by st.text_input().

In other words, insert the input and the selectbot options in unique row by merging these two streamlit methods together.

Is there another way to do this with html code??

3 Likes

Hi @oltipreka,

I think you can try doing something like this, take comma separated values of options and then feed its split to options.

import streamlit as st

inputs = st.text_input("Give csv of inputs")

st.selectbox("Select Dynamic", options=[opt.strip() for opt in inputs.split()])

If you want to take the values one by one it will be a little more complex as it will require you to hold the state. This snippet should do the job.

import streamlit as st
from state import provide_state


@provide_state
def main(state):
    state.inputs = state.inputs or set()

    input_string = st.text_input("Give inputs")
    state.inputs.add(input_string)

    st.selectbox("Select Dynamic", options=list(state.inputs))

main()

This will work like this,


Hope it helps !

PS. find @provide_state here, https://gist.github.com/ash2shukla/ff180d7fbe8ec3a0240f19f4452acde7

4 Likes

Dear @ash2shukla,

First, thank you so much for your effort. What you have suggested is exactly what I have been using.
However, I was looking to do the same thing but in only one box, instead of two.

Most probably, Streamlit does no provide something similar, though I was hopping in any existing hack :roll_eyes: :slightly_smiling_face: :slightly_smiling_face:.

Can any of @andfanilo @Adrien_Treuille @okld tell us something more about it?

Hi @oltipreka,

Staying in the realm of native Streamlit solutions, @ash2shukla’s solution is the closest you’ll get :slight_smile:, maybe you can hide the text_input in the sidebar or an expander to make it more “configuration box”, and the selectbox in the main container.

Otherwise you will need to build your own Streamlit component for this and customizing one of baseui’s components, that looks like a great component to do!

Best,
Fanilo

1 Like

Hello @oltipreka,

As stated by @andfanilo, the only way to achieve what you want is to build your own streamlit component.

You cannot merge a text input and a selectbox natively, but you can at least put them in the same row.
I’ve taken @ash2shukla’s code sample, and modified it accordingly.

I’ve also changed it to automatically select the last input in the selectbox:

import streamlit as st
from state import provide_state

@provide_state
def main(state):
    state.inputs = state.inputs or set()

    c1, c2 = st.beta_columns([2, 1])

    input_string = c1.text_input("Input")
    state.inputs.add(input_string)

    # Get the last index of state.inputs if it's not empty
    last_index = len(state.inputs) - 1 if state.inputs else None

    # Automatically select the last input with last_index
    c2.selectbox("Input presets", options=list(state.inputs), index=last_index)

if __name__ == "__main__":
    main()

PS: @ash2shukla I like your provide_state decorator, I may use it for an another alternative state implementation :smiley:

3 Likes

Thank you all for the valuable suggestions.
Wonderful support from the Streamlit Team :wink: :wink: :wink: :wink:.

3 Likes

Hello,
here is an alternative way to do it. If you are looking for a way to dynamically add/remove text fields

Demo:
Screen Recording 2021-09-07 at 18.01.34

Code:

def main():
    # add the key choices_len to the session_state
    if not "choices_len" in st.session_state:
        st.session_state["choices_len"] = 0
    
    # c_up contains the form
    # c_down contains the add and remove buttons
    c_up = st.container()
    c_down = st.container()

    with c_up:
        with st.form("myForm"):
            c1 = st.container() # c1 contains choices
            c2 = st.container() # c2 contains submit button
            with c2:
                st.form_submit_button("submit")

    with c_down:
        col_l, _, col_r = st.columns((4,15,4))
        with col_l:
            if st.button("Add Choise"):
                st.session_state["choices_len"] += 1

        with col_r:
            if st.button("remove Choise") and st.session_state["choices_len"] > 1:
                st.session_state["choices_len"] -= 1
                st.session_state.pop(f'{st.session_state["choices_len"]}')


    for x in range(st.session_state["choices_len"]): # create many choices
        with c1:
            st.text_input("text", key=f"{x}")
    
    # reads values from the session_state using the key.
    # also doesn't return an option if the value is empty
    st.selectbox("myOptions", options=[
        st.session_state[f"{x}"]\
        for x in range(st.session_state["choices_len"])\
        if not st.session_state[f"{x}"] == ''])

1 Like

Is state replaced by the new feature session_state? Otherwise I would use some of these examples here in my own dashboard.

Any updates about this discussion together with this Dynamic options update for dropdown.

There is a good dropdown solution in Dash ( see Dropdown | Dash for Python Documentation | Plotly). Hope Streamlit will fill the gap~

1 Like