Issue 2 (#10531) - joaooliveira-11/streamlit GitHub Wiki
Containers with background color
The issue
The issue can be found at https://github.com/streamlit/streamlit/issues/10531. The reported enhancement from streamlit is for adding the color parameter to the container element. The reporter of the issue mentions that this should be a new parameter named color and that it should accept the same values as the ones used in the markdown backgrounds. In order to be adopted, there shall be various tests with different elements including transparent elements and charts to make sure the background is well set.
Issue in practice
import streamlit as st
with st.container(background_color="blue", height=500):
st.subheader("Example transparent text with blue container background")
st.subheader("Example text which is placed outside of the container")
Why Does This Issue Matter?
There are several real world scenarios where having a background color in a container may be useful. It was pointed out by the Product Owner from streamlit that some of the possible use cases could be:
Creating a dashboard look with white cards on top of a gray background.
Callouts with more colors than what st.warning/st.info/st.success/st.error offer.
Highlighting a section of the app.
Apart from that, having a background color in the container can set the tone for impactful visual graphics and dashboards.
Requirements
This enhancement can be used in the context of any web-based application built using Streamlit, which is a Python framework for quickly building and deploying interactive web apps, particularly for data science and machine learning workflows.
User Story
- As a User, I want to be able to add a background color to a container element.
Expected Behaviour
Source Code Files
This issue required modifications in two main areas of the source code: backend classes related to Python and Protobuf logic for automatic JavaScript generation, and frontend classes related to rendering and styling logic. Additionally, associated tests were updated to ensure stability after the changes.
Files involved:
Backend Classes:
Protobuf definitions and backend layout logic:
- Block.proto — updated Protobuf schema to reflect layout changes.
- layouts.py — adjusted logic for interpreting and managing layout blocks.
- layouts_test.py — added and updated tests to cover the modified layout behavior.
- streamlit elements - used most of the existing elements to test the updated container logic
- st_container.py - the class used for playwright tests, with additions using the new container parameter
- errors.py - used to define a new error to be invoked upon using an unknown color in the new parameter
Application entry points and build processes:
- hello.py — used sample streamlit code to test the updated logic
- Makefile — used to update the logic according to the Protobuf changes
- st_altair_chart.py — tested widget logic to work with the new backend layout structure.
Frontend Classes:
Rendering and Component Structure:
- Block.tsx — updated main component for rendering layout blocks.
- frontend/lib/src/components/shared/StreamlitMarkdown/StreamlitMarkdown.tsx - used as reference for the background colors and color usage
- frontend/lib/src/components/elements/Markdown/Markdown.tsx — used as reference for needed styling changes
- PlotlyChart.tsx — used for testing and understanding the logic from the chart
Styling and Utilities:
- styled-components.ts — updated component styles to align with new layout specifications.
- getColors.ts — added logic for the new background colors for containers.
- types.ts — used for understanding theming structure
Testing:
- utils.test.ts — used existing tests as a guideline for developing the feature
Design of the Fix
In order to implement the feature, a new color parameter had to be added at the Python layer and in the Protobuf. Once the Protobuf was according to standards, the Makefile was ran to generate the updated javascript logic. With that, the parameter was accessible in the frontend classes inside the container if specified.
In the backend, there are validations being done in the new background color parameter, since the valid input values are defined in a Literal. If the value is not known, then a error is presented to the user showing the current value and the valid values.
Since the container element is associated with the Block class, the color parameter was used to set the background color of the StyledVerticalBlockBorderWrapper. Instead of using the native colors per known Strings such as "red" or "blue", the used colors were obtained using a new method called getContainerBgColors. This method uses the same color values as the getMarkdownBgColors, and checks the theme being used (either white or dark) to specify the correct color value
The biggest concern reported in this ticket was the need to apply this background color to transparent elements and charts. There were attempts to pass the background color to child elements via styling inheritance, however it was evasive and had no results working as expected.
The found workaround which was communicated to the engineering team from Streamlit was to set the background color of the charts as transparent upon building them in the Python invocation logic. Doing that, the background color for the components ended up being the one defined in StyledVerticalBlockBorderWrapper - which grants the flexibility for charts and elements to either have the same background as the theme or the same background as the container.
Diagram of the change
Fix Source Code
Source code changes in layouts.py
Added a new color parameter to the st.container element. Added the needed information in the docstring and added a new example using the parameter.
Source code changes in layouts_test.py
Added two new tests, one for using a known color value and another with an unknown color value. The purpose of tests was to make sure that any string value could be passed and that backend had no influence in the background color attribution (only the theme).
Source code changes in Block.proto
Added the new attribute with the identifier 3 to the Protobuf class.
Source code changes in Block.tsx
Obtains the backgroundColor from the proto interaction and then maps it to the correct color values by using the current theme and the provided background colors. Uses that value as the input for the VerticalBlockBorderWrapper
Source code changes in styled-components.ts
Added the backgroundColor parameter to the StyledVerticalBlockBorderWrapper. This makes sure that the entirety of the container is filled with the input color.
Source code changes in getColors.ts
Added a new method called getContainerBgColor which obtains the correct background color according to the value passed in the parameter. Uses the same color values as in the markdown but does a direct mapping.
Source code changes in st_container.py
Added playwright tests so that developers that want to interact with the new container (with background color) can do it directly
Source code changes in errors.py
Added a new custom error for when the user submits a background color which is not known
Submit The Fix
A pull request was submitted on the project's Github and can be found at https://github.com/streamlit/streamlit/pull/11206. Although not yet merged, it was well received by the product owner from streamlit and is under analysis by the engineering team.