How to change background color for SVG graphics with CSS?

Dear community! First of all thanks for providing Streamlit. It is such a great and wonderful tool and the app I develop would never be in its shape it is today without Streamlit (https://amfupapp.streamlit.app).

My system at the moment:
Python 3.12.4
Streamlit 1.39.0

I would like to enhance the user experience by introducing the dark app theme. I’m sticking with dark theme and SVG pictures at the moment. It is already there, but with my SVG graphics I come to the point that in dark mode the graphics get weird, below you find an example:

Light mode:


Same picture in Dark mode:

Inverting is no option for me as there are some graphics with a photo like style that would result in a negative of the picture. So I’m looking for a way to set the background of the SVG to white. I’m not experienced in CSS but my impression is that with CSS this could be done. So I would like to ask for your kind assistance. The preferred solution would be not to modify the SVG data itself but to inject some CSS code into the columns I use to display the SVG. Any hep would be great! No idea, if it is relevant for a solution, but in the text parts st.write also in combination the LaTex expression is used. Any help would be great, thank you in advance!

With CSS, you can target the div containing the SVG images. This will affect all images though:

div[data-testid="stImageContainer"]{
    background-color: pink;
    padding: 0.5rem;
}

How are the SVGs generated in the first place? It might be easier to set up a background color at that point than to modify them after.

1 Like

Thank you so much for giving support. This already looks very promising, I will give it a try! Please apologize my lack of knowledge regarding CSS Edwin (I really have to work on it) - so I would use a command like the following to implement it?

css = f"“”
div[data-testid=“stImageContainer”]{
background-color: pink;
padding: 0.5rem;
}
“”"
st.image(f"{css}")

Is this what I have to provide before the SVG are shown with something like st.image(svg_pic, width=300), where svg_pic is the path to my pictures?

You asked about the SVG themself. They are located in a folder /svgs/pic1.svg, /svgs/pic2.svg, …, about 500 of them, different width and height. A typical example of simple SVG is the following:

<svg xmlns="http://www.w3.org/2000/svg" width="180" height="44.451"><defs><clipPath id="a"><path d="M0 .078h34.879v43.754H0Zm0 0"/></clipPath><clipPath id="b"><path d="M13 .078h15V15H13Zm0 0"/></clipPath><clipPath id="c"><path d="M13 21h16v22.832H13Zm0 0"/></clipPath><clipPath id="d"><path d="M27 21h1v22.832h-1Zm0 0"/></clipPath><clipPath id="e"><path d="M21 22h13.879v15H21Zm0 0"/></clipPath></defs><g clip-path="url(#a)"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".7845110100000001" d="M34.488 21.957c0-8.66-7.02-15.684-15.68-15.684S3.126 13.297 3.126 21.957s7.023 15.68 15.684 15.68 15.68-7.02 15.68-15.68Zm0 0"/></g><g clip-path="url(#b)"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".39274767000000005" d="M27.738.273v14.165H14.063"/></g><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".7845110100000001" d="M14.063 11.215v21.484"/><g clip-path="url(#c)"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".39274767000000005" d="M14.063 21.957h13.87m-13.87 7.52h13.675v14.16"/></g><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".7845110100000001" d="M10.781 14.238v15.434"/><path d="M21.438 21.957v2.25l-5.032-2.25 5.032-2.254Zm0 0"/><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".39274767000000005" d="M10.781 29.477H.195"/><g clip-path="url(#d)"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".39274767000000005" d="M27.738 21.957v21.484"/></g><path d="M28.832 29.477a1.094 1.094 0 1 0-2.189.001 1.094 1.094 0 0 0 2.189-.001m0 0"/><g clip-path="url(#e)"><path fill="none" stroke="#000" stroke-miterlimit="10" stroke-width=".39274767000000005" d="M28.832 29.477a1.094 1.094 0 1 0-2.189.001 1.094 1.094 0 0 0 2.189-.001Zm0 0"/></g></svg>

I could imagine a batch job that inserts code in all the SVG, but I ask myself if this would be easier than the solution you proposed. A white background in Dark and White would do the job.

Almost, but not quite. CSS injections can be done using st.html(see st.html - Streamlit Docs). In your Python application, you’d write something like this:

css = """
div[data-testid="stImageContainer"]{
    background-color: pink;
    padding: 0.5rem;
}
"""
st.html(f"<style>{css}</style>")

I thought the SVGs were generated programmatically, like using some plotting library. Since that is not the case, the CSS injection should be easier.

1 Like

Fantastic - works perfectly, you saved my day, thank you so much! Edwin, may I ask a further question that is strongly connected with the dark/light topic and CSS of this thread? If you say please open another topic, this would be absolutely fine for me (and would probably help to keep things separated). The second issue with dark app schemes is as follows:
I use the absolutely beautiful Custom Component streamlet-tree-select (New Component: streamlit-tree-select, a simple and elegant checkbox tree). So useful to display and select hierarchies! Here something similar happens in dark mode: text is nearly invisible. How could I fix this with CSS? The issue was raised by others in the discussion linked above, but unfortunately it was never fixed. Here an example:

That is a different issue and it is more difficult because custom components live inside an iframe, and, afaik, you cannot target the style within an iframe with CSS alone. This seems to be a known issue for that component, and it was fixed but they never updated the package in PyPI:

Thank you for your answer, Edwin. So, in GitHub there is a commit for request #8 by the owner of streamlit_tree_select (Schluca) that should fix the problem (contributed by BlueGob). Schluca was asked several times to update in PyPI but, as you confirmed, this never happened. This is really a pity as the component was praised by so many user and I’m sure that the demand on dark mode will raise for several reasons (OLED displays, ergonomic, …). Is it possible to fork the repo and publish it - maybe after renaming, referring to the source and respecting the corresponding license - in PyPI? In order to reduce maintenance efforts I could imagine that an easy “pip install streamlit_tree_select_whatever_new_name” would be a better approach compared to the solution (more a hack) that was proposed, namely replacing a special css-file in the python environment. What do you think?

Of course! If the component was ready to be used with the code as it stands right now in GitHub, you could even install it with pip directly by clonning the repo:

pip install git+https://github.com/Schluca/streamlit_tree_select

However, that will raise this exception:

StreamlitAPIException: No such component directory: '/home/user/venv/lib/python3.12/site-packages/streamlit_tree_select/frontend/build' 

Because this component was being made using React (I think) and it needs to be built before Streamlit can actually use it. So just republishing a fork of the repository won’t be enough. There is a bit more info in the “Create a bi-directional component” section at Intro to custom components - Streamlit Docs about this.

It looks like people have been forking and republishing already! For example, check streamlit-tree-select2 · PyPI from GitHub - wenyuzhao/streamlit_tree_select: A simple and elegant checkbox tree for Streamlit.

streamlit-tree-select2


There is this other fork but they set the background color to always be white:

streamlit-tree-select-dark

1 Like

Edwin, this are mind blowing news! I did not expect that there is a PyPI package out there fixing the dark mode - so I didn’t even try. Instead I started reading the documentation for deployment on PyPI :slight_smile: . Thank you for your search, I just released a new version of my app and voila.

Your support was extraordinary, Edwin. I am glad that people like you help the beginners and guide them into the right direction. This took the app to a new level in the last few days. I hope that it will help many users to pass the radio amateur exam.

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