St.tabs collapse when used under button

Summary

Hi, I’m using streamlit-ace to configure a json editor. The issue here that I’m creating tabs using a button, and in one of the tabs I’m creating this editor. But as soon as I make any change to editor, the whole tab structure collapses.

Steps to reproduce

Code snippet:

import streamlit as st
from streamlit_ace import st_ace
import json


button = st.button("press")
if button:
    tabs = st.tabs(["1"])

    with tabs[0]:
        data = {"a" : "B"}
        content = st_ace(value=json.dumps(data, indent=2), language="json", theme="clouds_midnight", auto_update=True)
        content
        b = st.button("check result")
        if b :
            st.json(content)
            st.write(json.dumps(content, indent=2))

If applicable, please provide the steps we should take to reproduce the error or specified behavior.

Expected behavior:

I should be able to make changes in the editor and use those changes, but since everything is collapsing I can’t do that.

Actual behavior:

There are no errors. It’s just that since we’re producing tabs with a button, that’s why it’s behaving this way. If we were doing this without buttons, it would work flawlessly. But in my application, I need the run button.
PS - Any workaround would be appreciated. I tried dividing the tabs part into separate pages, so that its dependency on button can be eliminated, but imports are impossible.

Debug info

  • Streamlit version: streamlit==1.18.1
  • Python version: 3.8
  • Not working on Firefox or Chrome.

Requirements file

Links

Additional information

You have a nested button.

Check this thread for more info about how to deal with their state:

2 Likes

@edsaac Thanks for pointing me in the right direction!
I found this YouTube video that helped with getting a clear answer How to make NESTED buttons in Streamlit with Session State - YouTube
You have saved me a lot of trouble :slight_smile: much appreciated!

You can use https://extras.streamlit.app/Stateful%20Button as a pre-made version of this if you’d like

@edsaac @blackary Thanks for you inputs, but I am still facing an issue I’m not able to crack.

I am receiving data from database in one button called, let’s say, “Fetch Data”. Now I want to use this data (dataframe obj) in another button “Show Results”.

This is what the code for it looks like:

    if st.button("Fetch Data"):
        df = run_profiler(database=database, schema=schema, table=table, sampling_percent=sampling_percent)
        st.write("Evaluation complete. Click on Show Results to view the Profiling results.")
    show_results = button("Show Results", key="show_results")
    if show_results:
        st.dataframe(df)
        show_profiling_results(df)

I’m able to fetch the data in df, but not able to use that df variable outside the scope of the first if condition. I tried with both buttons (as mentioned above). What am I doing wrong here?
Preferably, I want the “Show Results” button to show up after the “Fetch Data” button is clicked, but if that’s not possible, I can make this work too!

NOTE: I saw that one of the solutions is to use checkbox instead of button, but in that case, when I click on “Show Results”, it goes back to the checkbox and runs the fetch query again (twice??), which will cause it to be very, very slow. And every time I make any change to the editor placed inside “Show results” it runs the fetch query.
Thanks in advance! :slight_smile:

Hi, I have found a way to use session_state to pass data between buttons, and to also avoid rerun of the entire app. Here is the code:

# Initialize Button State
    if 'fetch_data_state' not in st.session_state:
        st.session_state.fetch_data_state = False
    if not st.session_state.fetch_data_state:
        if st.button("Fetch Data"):
            st.session_state.fetch_data_state = True
            if 'df_state' not in st.session_state:
                st.session_state.df_state = None
            df = fetch_data(database=database, schema=schema, table=table,sampling_percent=sampling_percent)
            st.session_state.df_state = df
    if st.session_state.fetch_data_state:
        show_results = button("Show Results", key="show_results")
        if show_results:
            st.dataframe(st.session_state.df_state)

NOTE: The Show Results button is streamlit-extras button (to save state). Hope this helps!