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

image

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:

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

DiagramCES

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.

image image

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).

image

Source code changes in Block.proto

Added the new attribute with the identifier 3 to the Protobuf class.

image

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

image

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.

image

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.

image

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

image

Source code changes in errors.py

Added a new custom error for when the user submits a background color which is not known

image

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.