This is a tutorial on how to customise the appearance of your streamlit app using CSS. Within this tutorial I will:
- Introduce streamlit and set up a basic app
- Introduce CSS and the three methods you can use to incorporate it into your app
- Show a range of examples, customising: buttons, the sidebar, headings, ...
All the code used in this tutorial is available in this GitHub repository, and you can view the app produced in this tutorial on streamlit community cloud (add link).
Streamlit is a python-based framework for creating interactive web apps. Find out more at https://streamlit.io/.
We will begin by creating a basic streamlit app with a heading and a single widget. First you need set up your environment. One way to do this is with venv and a requirements.txt file. The text file should contain streamlit and any other packages you require - here, I've add numpy:
numpy==2.1.1
# Don't give streamlit version to ensure app has latest security updates
streamlit
To set up the environment, then run the following in your terminal:
# If not already installed:
pip install virtualenv
# Create new environment (here, named streamlit_css_tutorial)
virtualenv streamlit_css_tutorial
# Activate environment
source streamlit_css_tutorial/bin/activate
# Install packages from requirements.txt into the environment
pip install -r requirements.txt
We will then create a python file named 'Home.py' which will serve as our streamlit homepage. We'll add a header, some text and a button.
import streamlit as st
from numpy import random
st.title('Welcome to the app')
st.markdown('This is an example of a basic streamlit app.')
st.header('Random number generator')
if st.button('Generate random number from 0-10'):
st.markdown(random.randint(10))
To run your app, run the following in the terminal (with your virtual environment activated):
streamlit run Home.py
To customise our app, we will be using CSS. CSS is a style sheet language used to format HTML documents. It controls the layout, appearance and style of multiple HTML elements at once. It allows for seperation of content (HTML) and style (CSS) of webpages.
There are three ways to add CSS to a HTML document:
- Inline - inside element - e.g.
<h1 style='color:blue;'>A Blue Heading</h1>
- Internal - in head section - e.g.
<style> body {color: red;} </style>
- External - in .css file, linked to in head section
In this example, an external .css file if used, but the same code could be adapted to work internally or inline.
Using simple button example... explain difference ways of doing it, inline outside so on, show how you identify stuff with inspect... explain what div and li and stuff are as they come up
(for each of these, show how to add the widget, inspect, and customise)
/* Sidebar font color (as default is to set non-selected to more transparent */
[data-testid=stSidebarNavItems] > li > div > a > span
{
color: #05291F;
}
/* Title */
h1
{
text-align: center;
}
/* Expander */
div[data-testid=stExpander] > details > summary > span > div > p
{
font-weight: bold;
}
/* Text in status elements */
div[data-testid='stNotificationContentError'] > div
{
justify-content: center;
}
div[data-testid='stNotificationContentWarning'] > div
{
justify-content: center;
}
div[data-testid='stNotificationContentSuccess'] > div
{
justify-content: center;
}
div[data-testid='stNotificationContentInfo'] > div
{
justify-content: center;
}
/* Responsive font size adjustment */
/* On larger screen sizes (i.e. not mobile or very narrow browser window) */
@media only screen and (min-width: 600px)
{
/* Title */
h1
{
font-size: 60px;
}
/* Subheader */
h3
{
font-size: 30px;
}
/* Markdown p */
p
{
font-size: 20px;
}
/* Markdown lists */
div[class='stMarkdown'] > div[data-testid='stMarkdownContainer'] > ul > li
{
font-size: 20px;
}
/* Sidebar font size */
[data-testid=stSidebarNavItems]
{
font-size: 25px;
}
/* Selectbox title */
div[class*='stSelectbox'] > label > div[data-testid='stMarkdownContainer'] > p
{
font-size: 20px;
}
/* Selectbox chosen option - this targets element with CLASS name as given*/
.stSelectbox > div[data-baseweb='select'] > div
{
font-size: 20px;
}
/* Selectbox other options */
ul[data-testid=stVirtualDropdown] > div > div > li[role='option']
{
font-size: 20px;
}
/* Expander */
div[data-testid=stExpander] > details > summary > span > div > p
{
font-size: 20px;
}
/* Text input box label */
div[data-testid=stTextInput] > label > div > p
{
font-size: 20px;
}
/* Radio in sidebar */
/*div[class*='row-widget stRadio'] > label > div > p
{
font-size: 20px;
}*/
}
have used has:() to access these, so selecting the right ones
To change colour of line, can use border colour.
To make it thicker, use height and background colour.
/* Horizontal line */
div[class='stMarkdown'] > div[data-testid='stMarkdownContainer'] > hr
{
border-color: #D7D7D7;
margin: 0;
}
For multipage apps, the .css style outside will change styling on elements across the app. If you want to override this for one of the pages on that app and change styling of those elements to be different to elsewhere, you can do on page or inline or whatever its called.
example -
# Replace CSS styling of the buttons on this page
st.markdown('''
<style>
div.stButton > button:first-child
{
background-color: #D4ED6B;
border-color: #B0C74A;
}
</style>''', unsafe_allow_html=True)
/* Columns */
/* Force columns to remain on mobile view - otherwise collapses all columns */
/* Note: This is currently based on assumption of wanting 33% col size */
[data-testid="column"] {
width: calc(33.3333% - 1rem) !important;
flex: 1 1 calc(33.3333% - 1rem) !important;
min-width: calc(33% - 1rem) !important;
}
NOTE: Look through and see which use CSS
The Python library streamlit-extras contains several functions and user additions to streamlit, often created using CSS, which can serve as further inspiration for customising your app - or you can install and load that library and use their pre-created functions.
For example, the code I used to add a logo at the top of the sidebar above is based on the source code of their function app_logo().
Recommended functions to check out include the styleable_container().