Reputation: 992
Hi all I am building a simple web app with streamlit in python. I need to add 3 buttons but they must be on the same line.
Obviously the following code puts them on three different lines
st.button('Button 1')
st.button('Button 2')
st.button('Button 3')
Do you have any tips?
Upvotes: 20
Views: 36602
Reputation: 572
If you're like me, it might bother you that the columns equally space, making layout not visually appealing because the buttons appear far apart.
After a lot of CSS digging, I found a pretty simple approach that doesn't require any other library installs. It is possible (at least for the current version of streamlit) to apply the following CSS to make columns only as wide as the button. I included this at the top of my file:
st.markdown("""
<style>
div[data-testid="stColumn"] {
width: fit-content !important;
flex: unset;
}
div[data-testid="stColumn"] * {
width: fit-content !important;
}
</style>
""", unsafe_allow_html=True)
And then (for my use case):
col1, col2, col3 = st.columns([1,1,1])
with col1:
st.button(...)
with col2:
st.button(...)
with col3:
st.download_button(...)
Upvotes: 9
Reputation: 151
I wanted to point out that sometimes you might want 2 buttons right next to each other. I've adapted some of these solutions to line up two buttons (in this case a thumbs up and thumbs down) to be right next to each other. The trick is to use a 3rd column for buffering so that the buttons can be next to each other. This can be resized to apply for different conditions.
Here is the code:
col1_, col2_, col3_ = st.columns([1,1,12])
with col1_:
st.button("👍")
with col2_:
st.button("👎")
with col3_:
pass
Upvotes: 4
Reputation: 57195
Generalizing this answer a bit to use a dynamic number of buttons:
import streamlit as st # 1.18.1
button_text = "foo", "bar", "baz"
for text, col in zip(button_text, st.columns(len(button_text))):
if col.button(text):
col.write(f"{text} clicked")
If the text isn't necessarily unique:
button_text = "foo", "bar", "foo"
pairs = zip(button_text, st.columns(len(button_text)))
for i, (text, col) in enumerate(pairs):
if col.button(text, key=f"{text}-{i}"):
col.write(f"{text}-{i} clicked")
Upvotes: 4
Reputation: 905
I had a similar problem - to add an action button to a table. I came to the following approach:
import streamlit as st
# # Show users table
colms = st.columns((1, 2, 2, 1, 1))
fields = ["№", 'email', 'uid', 'verified', "action"]
for col, field_name in zip(colms, fields):
# header
col.write(field_name)
for x, email in enumerate(user_table['email']):
col1, col2, col3, col4, col5 = st.columns((1, 2, 2, 1, 1))
col1.write(x) # index
col2.write(user_table['email'][x]) # email
col3.write(user_table['uid'][x]) # unique ID
col4.write(user_table['verified'][x]) # email status
disable_status = user_table['disabled'][x] # flexible type of button
button_type = "Unblock" if disable_status else "Block"
button_phold = col5.empty() # create a placeholder
do_action = button_phold.button(button_type, key=x)
if do_action:
pass # do some action with row's data
button_phold.empty() # remove button
And it works fine. The object — user_table
— is a dictionary very similar to DataFrame, where each key — is a column (i.e. list
in pythonic terms).
And here how it looks like (Note “Blocked” — that is the result of action):
Upvotes: 3
Reputation: 992
Apparently this should do it
col1, col2, col3 = st.columns([1,1,1])
with col1:
st.button('1')
with col2:
st.button('2')
with col3:
st.button('3')
Upvotes: 33