following this discussion, I wanted to add some context buttons close to the chat input for our app. I tried with a single toggle button for the camera and it positioned it nicely, like this:
The problem is when there is enough text to fill up the entire chat area and then the text of the chat hides behind the icons float, specially in mobile (and we need the site to work well in mobile). Like this:
I ran into the same problem in the discussion you linked (presented by @pierrelouisbescond) and my quick and dirty solution was just to add 1 or 2 lines of st.write("") right after all the chat messages. This adds blank space at the end that will be covered up instead of the text. It works great while using streamlit functions. I would recommend adding a comment explaining why the lines are there in case you forget in the future or to inform someone else reading the code.
A cleaner solution imo would be to add padding to the bottom of the container with the scrollbar or alternatively, setting max-height to calc(100vh - HEIGHT_OF_PROMPT_AND_BUTTONS) where HEIGHT_OF_PROMPT_AND_BUTTONS is just some fixed value should provide the necessary vertical shift. Doing the latter has the added benefit of shifting the end of the scroll bar up to where the chat portion ends which I think is probably a cleaner look.
I would try the simple solution first and then maybe later work on the CSS approach.
On another note, I noticed that on mobile, your buttons are much higher up. What is the CSS you used to place the buttons? Did you use percentage or some window scale units?
Scratch that, the st.writes worked fine! Although I needed 8 because the button is so high in mobile and it looks a bit weird. I notice that if I manipulate the screen size with the developer tools on the browser, the button is mostly positioned similar than on the desktop until some point and then it jumps upwards suddenly. Any idea how to handle that?
I think it is flex-wrap judging by what devtools is showing me.
Can you provide another pic of what the css you added changed?
After playing around a little bit. You can fix the problem with CSS but it is very involved because you have to basically undo what Streamlit does when the screen gets to mobile size, but only undo it for the buttons and not everything else. Streamlit turns columns into rows when the screen gets small in width and then it makes each item full width.
One trick that might work since you dont have many buttons is to put the buttons in another column like this:
[ [ button 1 , button 2 ] , [ empty space , empty space, empty space ] ]
So basically an outter 2 columns with the first column containing the buttons (in another 2 column arrangment) and the second outer column contains empty inner columns.
There might be an even easier solution, but I cant know until I see your column setup for the buttons
I take back the idea about the nested columns. It doesnt work.
Yeah, so basically, the forceful way is to undo the streamlit css for small screens and add your own and making sure the changes only target the buttons and doesnt effect the rest. Its all doable but much more involved.
As you can see the icon moves to the left in the mobile version which probably means stacking. I was wondering if I could detect vertical stacking happening then maybe I can arrange the icons inside a popover, like they asked here
Anyways thanks so much for all the help, youâve helped me a lot.
I just saw your message. You caught me at a good time. I just had my coffee and some time to clear my thoughts.
I found a better solution to your problem. I realized that with float functions we can add any CSS we want to containers and that means we can position the contents of the containers wherever we want! So why do we even need columns to position buttons next to each other when we can use a container for each button and literally position them next to each other!! That way, we completely avoid the column behavior when the screen width is small!
Sure enough it works!
Instead of in a column. Put each button in a container.
con1 = st.container()
con2 = st.container()
with con1:
float_parent("bottom: 6.9rem;background-color: var(--default-backgroundColor); padding-top: 0.9rem;")
if st.button(...):
# Do stuff when first button clicked
with con2:
float_parent("margin-left: 6rem; bottom: 6.9rem;background-color: var(--default-backgroundColor); padding-top: 0.9rem;")
if st.button(...):
# Do stuff when second button clicked
All I did was float each button container separately and make sure to move the second button to the right by adding margin-left to the CSS and setting the value of the margin to be the width of the first button.
If I were to add a 3rd button, then I would set the left margin to the combined width of the first 2 buttons.
Now, there is no funny business with the media query changing the layout!
This is amazing! It works perfectly to avoid the button stacking. Thanks so much for the help @bouzidanas.
I have been fiddling with this and Iâm very satisfied with the result.
The only thing I was wondering. Right now it is easy to position all the buttons starting on the left of the screen because we have margin-left 0 there and then start increasing that gradually for the rest of the bottoms like you suggested. Do you know a trick to dynamically place a button on the right side of the screen (no matter the screen size), like where the chat input ends? I would like to position the camera icon there and other controls like delete chat on the left side but I havenât figured out how to.
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking âAccept allâ, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.