What is a difference between an `if` block and `on_click` for a button?

Is there any difference between

if st.button("Button with if"):


st.button("Button with callback", on_click=st_callback)

where st_callback is a user-defined function?

In both cases, clicking on the button causes a re-run of the app, at least in this simple example:

import streamlit as st
if 'cnt' not in st.session_state:
	st.session_state.cnt = 0
def bt_callback():
	st.session_state.cnt += 1
if st.button("Button with if"):
st.button("Button with callback", on_click=bt_callback)
st.write(f"{st.session_state.cnt = }")

Here, balloons are released after every click on either of the buttons.

And if there is difference, can you provide an example illustrating it? I have not found anything in the documentation.

Hi @mkaut

Thanks for the question. In essence, Streamlit reruns the app upon widget interaction (e.g. triggered by on_click or on_change). To preserve variables from losing their values during the rerun, one can use Session state for that. In your example, your preserving the variable values through the use of session state. So in spite of the app reruns (as noticed from the balloons going off in your app), the count value was added to session state and thus is preserved.

There’s a similar thread here:

Also, in the Docs, there is a short mention of this here (Main concepts - Streamlit Docs):

Then every time a user interacts with a widget, Streamlit simply reruns your script from top to bottom, assigning the current state of the widget to your variable in the process.

Hope this helps!

Best regards,

Thanks, but it does not answer the main question: is there any functional difference between using on_click= and putting the button to an if-block?
Or, to put it differently, why does button have on_click at all?


In the above mentioned thread, the difference between callbacks and if was explained by @mathcatsand (link to the specific message is Explaining run logic with buttons - #2 by mathcatsand)

As also mentioned earlier, the app reruns upon widget interaction. In the Docs, you can see that st.button (is also a widget) will have a on_click, while other widgets such as st.slider, st.text_input, st.selectbox, etc. will have on_change.

Hope this helps :slight_smile:

Best regards,

1 Like

Thanks again - and sorry, I should have read the whole thread, not only the quote…

To me, the crucial piece of information is this:

The key is that the callback happens before the page loads.

In other words, the counter will have the increased values for the whole re-run of the script if used with on_click, and only after the button if we use a button with if-block - good to know!

1 Like

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