I have two buttons in the same row that i want to a different Background colour for each. Please i have tried all the Css selectors known to man Nothing seems to work
Thanks for your code. Do you know how could I change this piece of code so I can change the buttonās color based on the key value? My buttons share the same label name but comes with different key value, so I could not do it using the label names.
The widget key is not accessible on the front end, so you canāt do that directly. You would need to use the context of other items around your buttons, or possible nth-of-type selectors to pick out your buttonsā¦which becomes very dependent on your exact code and situation.
Hereās a quick answer based on the same mechanism of using the label to color the buttons, It needs a little extra tweak if you want the button font color to remain the hover color after itās clicked instead of just having the box shadow linger. Itās set for dark mode, but there are lines at the top for you to switch out if you are in light mode or have a custom theme.
If you use the other mechanism I mentioned with nth-of-type selectors, you can get away with simpler CSS instead of JavaScript, but thatās just trading one kind of mess for another.
import streamlit as st
import streamlit.components.v1 as components
#if you have specified a theme, you can get the border color with:
#border = st.get_option('theme.secondaryBackgroundColor')
#border = 'rgb(49,51,63,.2)' #light mode
border = 'rgb(250,250,250,.2)' #dark mode
def ChangeButtonColour(widget_label, font_color, hover_color, background_color='transparent'):
htmlstr = f"""
<script>
var elements = window.parent.document.querySelectorAll('button');
for (var i = 0; i < elements.length; ++i) {{
if (elements[i].innerText == '{widget_label}') {{
elements[i].style.color ='{font_color}';
elements[i].style.background = '{background_color}';
elements[i].onmouseover = function() {{
this.style.color = '{hover_color}';
this.style.borderColor = '{hover_color}';
}};
elements[i].onmouseout = function() {{
this.style.color = '{font_color}';
this.style.borderColor = '{border}';
}};
elements[i].onfocus = function() {{
this.style.boxShadow = '{hover_color} 0px 0px 0px 0.2rem';
this.style.borderColor = '{hover_color}';
this.style.color = '{hover_color}';
}};
elements[i].onblur = function() {{
this.style.boxShadow = 'none';
this.style.borderColor = '{border}';
this.style.color = '{font_color}';
}};
}}
}}
</script>
"""
components.html(f"{htmlstr}", height=0, width=0)
cols = st.columns(4)
cols[0].button('first button', key='b1')
cols[1].button('second button', key='b2')
cols[2].button('third button', key='b3')
cols[3].button('fourth button', key='b4')
ChangeButtonColour('second button', 'red', 'blue') # button txt to find, colour to assign
ChangeButtonColour('fourth button', '#c19af5', '#401000', '#354b75') # button txt to find, colour to assign
Hey everyone, as this topic seems to be somewhat active and my question is somewhat fitting, I would like to follow up on the questions above I am new to CSS styling and html so please excuse if my question very simple.
I want to individually style each button without creating columns (the buttons should be below one another). Meaning I have 3 sidebar buttons, and I want each of them to have a separate background image that is loaded via a web-link (e.g., the first being an image of the sun, second of earth and third of the moon).
So far I only managed to either style all buttons or none. Do you have any tips / helpful code snippets?
The code snippets above should work. The fact that the example put the buttons in columns is completely separate from the mechanism of apply custom colors, so just copy the example above and delete the part where the columns are created and buttons are put into the columns; add buttons to render where you want and you should be good with simple replacements of your labels and colors that you want.
Does anyone have any clarity about why Streamlit is like this? I work on Shiny, which lets you pass CSS styles or classes directly to UI components, and I was really surprised to learn that Streamlit users have to go through this whole window.parent.document.querySelectorAll process to do something that seems pretty fundamental to building a website. There must be a good reason for it, but Iām at a loss to figure out what it is.
In my understanding, there is not a lot of demand for functionalities that allow easier modifications of the UI. Therefore, the community has developed a lot of āhacks.ā Streamlit was created as a tool for data scientists and not necessarily for front-end developers. With finite resources, the Streamlit team focuses on core functionalities.
Thatās really interesting. I wonder if demand is somewhat related to the framework decisions. For example in Shiny weāve always had full support for UI customization, and itās very common even among folks who donāt have any CSS background.
Hereās how you would do this in Shiny, and I donāt think it would be that hard to implement similar functionality in Streamlit unless thereās some internal reason it wouldnāt work.
Hello, based on the previous pieces of code, I made this code in the form of a class, so that it can be called. You can put whatever you want inside the button, although I havenāt tested mixing it with CSS styles. You can improve it if you like, but now you can modify the content without needing to create a column. This is the code.
custom.py file:
import streamlit.components.v1 as components
import streamlit as st
import json
class Button_Material():
def __init__(self):
self.key_dict = []
st.write('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"/>', unsafe_allow_html=True)
def generate_material(self,content,key):
button_dict = {'key':key, 'content':content}
self.key_dict.append(button_dict)
return {'label':key,'key':key}
def show(self):
icon_config = f"""
<script>
var elements = window.parent.document.querySelectorAll('button');
let attrib = {json.dumps(self.key_dict)};
for (var i = 0; i < elements.length; ++i) {{
for (var j = 0; j < attrib.length; ++j){{
if (elements[i].innerText == attrib[j].key) {{
elements[i].firstChild.innerHTML = attrib[j].content;
}}
}}
}}
</script>
"""
components.html(f"{icon_config}", height=0, width=0)
test.py file:
import streamlit as st
import custom
bt_custom = custom.Button_Material()
#Test
st.button(**bt_custom.generate_material('<img src="https://images.hdqwalls.com/download/flower-mod-pic-240x320.jpg">','button_test_1'))
st.button(**bt_custom.generate_material('<p><i class="fa-brands fa-youtube"></i> hola</p>','button_test_2'))
st.button('test')
bt_custom.show()
The idea is to first create a button with the same label and key, and then change all the affected buttons at the end.
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.