Issue with Modifying Text using st.text_input and st.button

I’m encountering an issue with Streamlit where I’m trying to allow the user to modify text using st.text_input and then display the modified text when a button is clicked. However, the modified text is not persisting as expected in the session state.

Here’s a simplified version of the code:

import streamlit as st

# Initialize session state
if 'text' not in st.session_state:
    st.session_state.text = "original"

if st.button("show"):
    # Allow the user to modify the text
    st.session_state.text = st.text_input("Edit Text", value=st.session_state.text)

# Display the modified text
st.markdown(st.session_state.text)

if st.button("show again"):
    # Display the modified text
    st.markdown(st.session_state.text)

Despite using st.text_input to modify the text, the “show again” button still displays the original text, not the modified one. I’ve tried using st.text_area as well, but the issue persists.

Can anyone help me understand why the modified text is not persisting in the session state as expected? Any guidance or suggestions would be greatly appreciated!

hi @Raphael_Fabre

The issue you are encountering is related to the way Streamlit handles the session state and the rendering of elements. When you use st.text_input or similar widgets inside a button callback, the changes made by the user are not immediately reflected in the session state. This is because Streamlit does not re-run the entire script in response to a button click.

To address this, you can use the text_input widget directly to capture the user input, and then update the session state with that input.

Here’s an updated version of your code that should work as expected:

import streamlit as st

# Initialize session state
if 'text' not in st.session_state:
    st.session_state.text = "original"

# Allow the user to modify the text
modified_text = st.text_input("Edit Text", value=st.session_state.text)

# Update session state when the user modifies the text
if modified_text != st.session_state.text:
    st.session_state.text = modified_text

# Display the modified text
st.markdown(st.session_state.text)

if st.button("show again"):
    # Display the modified text
    st.markdown(st.session_state.text)

Note:
Streamlit’s session state handling is based on variable equality, so it’s essential to check for changes explicitly if you want to update the session state based on user input.

I’m facing something similar to this issue, actually pretty sure it’s the same problem but with different direction with components and state handling.

I have a st.input cached into a variable and then a st.button to send the cached variable to a firebase firestore connection. The code is something like:

def save_info(info):
  firebase_save_info(info)

myvar = st.input("My label", "Placeholder")
st.button("Send", on_click=save_info, args=[myvar])

The real problem is:
when I change the value in the input field and click directly in the button, it’ll send an empty string. If I do click somewhere else before the button, streamlit will run the value change in input and then it’ll send the correct info in the button args.

Guess what the user will do instead of clickg somewhere… Does anyone know any workaround for that?

I can’t reproduce the issue with your code.

I was trying to set up my example and I was afraid that I was saying something wrong just in my mind. So I re-run the tests and actually, my example would work pretyy fine, but my real code is a little bit messy.

The real code is somehitng like this:

import streamlit as st

def save_info(info):
  print(info)

columns = st.columns(2)

for i in range(len(columns)):
    with columns[i]:
        myvar = st.text_input("My label", placeholder="Placeholder", key="another-%d"%i)
        st.button("Send", on_click=save_info, args=[myvar], key="something-%d"%i)

myvar

and the problem is inside this range loop I guess.

I saw another answer in another thread saying that we can’t ‘force’ the value in any input widget do update itself. So, the question stays the same, how to handle the text_input update in a range loop?

This might sound funny but I found the solution using the key argument from text_input. I’m learning Streamlit now and the docs sounds a little confusing. I’m gonna share my current test to set everythign working.

columns = st.columns(2)

for i in range(len(columns)):
    with columns[i]:
        info = st.text_input("My label",
            placeholder= "Placeholder",
            key= "another%d"%i)

st.session_state["another0"]

Thank you for your answers and directions in the other thread. I recommend anyone having this trouble to see the linked thread above and watch the video about streamlit states.