Disable the button until the end of the script execution

How can I disable the button after clicking it until the script finishes executing?

Thank you all

1 Like

Can you explain your situation a bit more? As soon as you click a button, the page will reload so I’m not entirely clear what logic flow you have in mind. There is a keyword parameter to disable buttons, but widgets aren’t change within a single execution after they are rendered; they can be updated in between renderings (page loads).

Let me give an example

if st.button(label=“start”):
st.write(“Yes”)
time.sleep(5)
st.write(“No”)

The above code will take about 5 seconds to run. I want the button to be disabled while the script runs so that the user can’t click it again.
After finishing the execution, the button should be activated again and can be used

1 Like

Here is an example modeled off of yours:

import streamlit as st
import time

if 'run_button' in st.session_state and st.session_state.run_button == True:
    st.session_state.running = True
else:
    st.session_state.running = False

if st.button('Do a thing', disabled=st.session_state.running, key='run_button'):
    status = st.progress(0)
    for t in range(10):
        time.sleep(.2)
        status.progress(10*t+10)
    st.experimental_rerun()

Depending on what you are going for, you may instead want to use a callback with the button to perform your operation. Callbacks run as a prefix to the next page load so you wouldn’t have to manually handle disabling the button. However, if you are wanting to render things on the screen as part of the process (as opposed to at the end of the process), then callbacks may introduce an extra snag since anything written to the screen during a callback goes at the top of the page before the main contents.

Thank you for your help, but in this case, any data that was supposed to be displayed on the screen will be lost when the button is activated.

Even if the rerun wasn’t there, you would lose everything under the button as soon as the user interacted with anything else on the page, just to be clear.

What exactly are you showing under the button that you want to keep? Can your write that data to session state and display it after the fact?

Alternatively, you may be able to play a trick with containers or moving some of the logic around. If the process is executed before the button is rendered, you could avoid messing with disabling it.

This would let the results remain on the page after the button click, but it will still go away when the user does something else:

import streamlit as st
import time

upper = st.container()
upper.write('Some content here')
lower = st.container()
lower.write('Some other content')

if 'run_button' in st.session_state and st.session_state.run_button == True:
    status = lower.progress(0)
    for t in range(10):
        time.sleep(.2)
        status.progress(10*t+10)
    lower.write('Some results here')

upper.button('Do a thing', key='run_button')

If you want it to stay there, then instead of conditioning it on the button directly, you would want to update some flag in session state from the button click and use that instead. Some examples here:

EDIT: Oops, the button will be show greyed out while running with this, but won’t be properly disabled. Perhaps it could be removed using st.empty so that the button just disappears while the page is loading instead. Your cleanest answer would be to use my first example and save your output to session state so you can display it after the fact rather than during the processing.

I want to display an image scraped by Selenium.
And as long as Selenium is running, the button will be disabled

1 Like

So then you just need to save your output in my first example so it can be displayed afterwards:

import streamlit as st
import time

if 'run_button' in st.session_state and st.session_state.run_button == True:
    st.session_state.running = True
else:
    st.session_state.running = False

if st.button('Do a thing', disabled=st.session_state.running, key='run_button'):
    status = st.progress(0)
    for t in range(10):
        time.sleep(.2)
        status.progress(10*t+10)
    st.session_state.output = 'Selenium Output'
    st.experimental_rerun()

if 'output' in st.session_state:
    st.write(st.session_state.output)
2 Likes

thank you very much
you are amazing

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.