Bugs when using st.tabs() : keeps jumping to first tab + glitch

Hello,

I have encountered 2 bugs when using st.tabs (with buttons): each time I click a tab it jumps bac to the first one, and each time I click a button there’s a glitch where all the hidden content of the tabs is shown all at once while the code is executing in the background

Here’s a demonstration:
Vidyard Recording?

Here’s the code:

import streamlit as st
import time
import requests
import json

# App title:
st.title("Pseudonymization demo")

# App description:
st.markdown("_This app allows you to pseudonymize your personal data._")

# Blank space:
st.write(" ")

# Sidebar container:
with st.container():
    st.sidebar.title("Configs")
    language = st.sidebar.selectbox("Language", ("French", "English", "Spanish"))
    user_id = st.sidebar.text_input("User ID", placeholder="Your ID here...")
    entities = st.sidebar.text_input("Entities", value="ALL")


# App tabs:
tab1, tab2, tab3 = st.tabs(["Pseudonymization", "Anonymization", "De-pseudonymization"])


# Pseudonymization tab:
with tab1:
    
    st.write("")
    
    # Input text to pseudonymize:
    input_text = st.text_input("**Text to pseudonymize:**", placeholder="Enter your text here...",)

    # Button to pseudonymize:
    if st.button("Pseudonymize"):

        # Blank space:
        st.write(" ")
        st.write(" ")
        with st.spinner('Wait for it...'):
            result = st.write("**Pseudonymized text:**")
            st.info(' _EXAMPLE_OUTPUT_')
            st.success('200', icon="✅")

            st.write("___")
            with st.expander("See JSON response"):
                st.json({
                        'user_id': user_id,
                        'text': 'EXAMPLE_OUTPUT',
                        'lang': language,
                        'entities': [
                            'ent A',
                            'ent B',
                            'ent C',
                        ],
                    })


with tab2:

    st.write("")

    # Input text to anonymize:
    input_text = st.text_input("**Text to anonymize:**", placeholder="Enter your text here...")

    # Button to anonymize:
    if st.button("Anonymize"):

        # Blank space:
        st.write(" ")
        with st.spinner('Wait for it...'):

            # Request to the API:
            url = "URL_EXAMPLE"

            # Request body:
            payload = json.dumps({
            "user_id": f"{user_id}",
            "text": f"{input_text}",
            "lang": f"{language}",
            })

            # Request headers:
            headers = {
            'Content-Type': 'application/json'
            }

            # Send the request:
            response = requests.request("POST", url, headers=headers, data=payload).text
            result = st.write(f"**Anonymized text:** {response}")
            st.write(" ")
            st.success('200', icon="✅")
            

with tab3:

    st.write("")

    # Input text to de-pseudonymize:
    input_text = st.text_input("**Text to de-pseudonymize:**", placeholder="Enter your text here...")

    # Button to de-pseudonymize:
    if st.button("De-pseudonymize"):

        # Blank space:
        st.write(" ")
        with st.spinner('Wait for it...'):
            # Request to the API:
            url = "URL_EXAMPLE"

            # Request body:
            payload = json.dumps({
            "user_id": f"{user_id}",
            "text": f"{input_text}",
            })

            # Request headers:
            headers = {
            'Content-Type': 'application/json'
            }

            # Send the request:
            response = requests.request("GET", url, headers=headers, data=payload).text
            result = st.write(f"**De-pseudonymized text:** {response}")
            st.write(" ")
            st.success('200', icon="✅")

To be honest, I don’t really understand why this is happening, but it is somehow related to the st.container() that you are wrapping around the st.sidebar calls. If you instead do this, the tab switching seems to go away:

with st.sidebar:
    st.title("Configs")
    language = st.selectbox("Language", ("French", "English", "Spanish"))
    user_id = st.text_input("User ID", placeholder="Your ID here...")
    entities = st.text_input("Entities", value="ALL")

However, if a cached resource is introduced somewhere before the sidebar, e.g.

    @st.cache_resource
    def get_session():
        # Create an HTTP session
        print("called get_session")
        return requests.Session()
    
    session = get_session()

    # Sidebar container:
    with st.sidebar:
        st.title("Configs")

then the problem persists; that is, the app often jumps back to tab1. For my applications, this makes the use of tabs very unappealing.

1 Like

I am happy to report that with release 1.25.0, this problem appears to be solved. It was related to this bug:

:bug: Bug Fix: Elements no longer re-render from scratch with each rerun (#6923, #6920).

1 Like