Returning to the right tab after clicking button

I have an app with three tabs, and some buttons in the sidebar. When a button is clicked, running a function and processing some things in session_state, the app will always return to the first tab, when I would prefer it to remain on the tab that was open when the process was run.

Any ideas on how to do this? Thanks :+1:

1 Like

@altanner Unfortunately, as st.tabs works today it’s purely a visual component and there’s no way to interact with it programmatically (e.g. to see which tab was clicked, or force a certain tab to be clicked). The simplest alternative I can recommend is to swap out tabs with something like a selectbox, which by default saves its state between app runs.

1 Like

Thanks for your ongoing help and information @blackary !

Hope this becomes something that Streamlit implement. It’s not a real biggie, but for my app I am trying to make it so users can flit between tabs for different views of their data, plus have action buttons which are always visible in the sidebar. Will keep my eyes open for future updates.

1 Like

Feel free to put a request for this functionality on Issues · streamlit/streamlit · GitHub – I know a number of people have mentioned this idea on the forum, but I don’t think I see an issue requesting this functionality currently on github.

Well, I think of doing that, but then go “crikey 526 issues… I don’t want to pile on even more… and it’ll just get lost and forgotten in this avalanche anyway”.

But maybe that is normal for a repo? I get anxiety issues if I have more than 2 or 3 issues on a repo. Is trillions of issues just how things work?

It depends what you compare it to. I think for large OSS projects that have a large userbase, having a large number of open issues is fairly normal (see Issues · matplotlib/matplotlib · GitHub for example). That being said, the streamlit open-source team definitely does pay attention to the issues (there are 2k+ closed issues, after all), and especially to issues that get lots of :+1:s. So, even if it doesn’t get addressed right away, having an issue page to discuss a desired feature can be a good place for the community to give feedback about how much they want this new feature, and how they would like to see it work.

I am unable to replicate your issue. The code below displays two tabs and one button in the sidebar. When the button is clicked a function is called and some things in session_state are processed, yet the selected tab doesn’t change --for me at least.

Adding more tabs, buttons, processing and state don’t seem to make any difference.

def do_stuff():
    st.session_state["counter"] += 1


if "counter" not in st.session_state:
    st.session_state["counter"] = 0

if st.sidebar.button("Do stuff"):
    do_stuff()

tab1, tab2 = st.tabs(["tab1", "tab2"])
tab1.metric("Counter", st.session_state["counter"])
tab2.metric("Squared counter", st.session_state["counter"]**2)

thanks @Goyo - this is a really useful test. let me have a look at what might be triggering a tab reset, for me, in more detail.

@altanner, did you ever figure this one out? I seem to be having a similar issue. The first interaction on my Streamlit app resets the selected tab to the first one. With subsequent interactions the selected tab is maintained. Running @Goyo’s example on the same environment works without a problem.

Hi all, Today I ran into the same issue. Also for me, running @Goyo 's example works fine. However, I was able to manipulate his example a little bit to let others reproduce the issue. I got inspired by my own use case, where we have a login button for users to authenticate before activating the dashboard.

In order to reproduce the issue, you can run the folllowing code:

import time

import streamlit as st


def do_stuff():
    st.session_state["counter"] += 1


if st.sidebar.button("login"):
    with st.spinner("please wait"):
        time.sleep(3)
        st.session_state["user"] = "foo"


if "user" in st.session_state:
    if "counter" not in st.session_state:
        st.session_state["counter"] = 0

    if st.sidebar.button("Do stuff"):
        do_stuff()

    tab1, tab2 = st.tabs(["tab1", "tab2"])
    tab1.metric("Counter", st.session_state["counter"])
    tab2.metric("Squared counter", st.session_state["counter"] ** 2)
  1. press the login button
  2. navigate to tab2
  3. click Do stuff
  4. The dashboard goes back to tab1

This happens only once, like @nicomunting says. As of the second time the page remains on the right tab.

How to solve?
I don’t have a real satisfying solution, but I noticed the issue is caused by any streamlit widget you pass after the login button. In this example a st.spinner, but it also happens with st.write, st.text, etc… If you remove any Streamlit widget, than the issue won’t occur. So, this works:

if st.sidebar.button("login"):
    time.sleep(3)
    st.session_state["user"] = "foo"
3 Likes

It is good having a runnable example. I managed to simplify it even futrther.

import streamlit as st


if st.button("Click here first"):
    st.button("Go to tab2 and click here")

tab1, tab2 = st.tabs(["tab1", "tab2"])
3 Likes

@olafdeleeuw and @Goyo , thanks for the examples. In both cases I get the behaviour that the app switches back to the first tab upon interaction. I guess we should report an issue on GitHub?

There is already an issue on Github and I posted a reply to this thread: Component in tab 2 triggers app to jump back to tab 1 · Issue #6257 · streamlit/streamlit · GitHub

1 Like

I just added a response to the GitHub issue as well. I worked from @olafdeleeuw’s example and simplified it further. Then I saw @Goyo’s simplification above and added another note.

The triggering condition is some difference in frontend state occurring before the tabs are defined. (e.g. having a line that is written conditionally, or using a spinner on some page reruns and not others). As a workaround, try making sure your tabs are defined ahead of any conditional content if you can.

For example, I can modify @Goyo’s example to avoid the error:

import streamlit as st

con = st.container()
tab1, tab2 = st.tabs(["tab1", "tab2"])

if con.button("Click here first"):
    con.button("Go to tab2 and click here")
2 Likes

Thanks @mathcatsand. Good to know what triggers this issue exactly. Now I can implement your workaround and define the tabs before the spinner, which in my case triggers the issue, to get rid of the issue. It would be nice of course if this is fixed at some point.

1 Like