Is it possible to create a sticky header on streamlit apps?
I have seen a few examples or other posts but with vague solutions or just not working ones.
In general what I want is to leave a section of my streamlit app sticky on top so that when I scroll down, it stays on screen.
Here is the solution i ended up using to create a sticky header.
It is possible to create a div with a specific class-name inside the streamlit container you want to use as your header. Then using the new css has() pseudo class you can target the parent of the div you created and make it sticky.
import streamlit as st
header = st.container()
header.title("Here is a sticky header")
header.write("""<div class='fixed-header'/>""", unsafe_allow_html=True)
### Custom CSS for the sticky header
st.markdown(
"""
<style>
div[data-testid="stVerticalBlock"] div:has(div.fixed-header) {
position: sticky;
top: 2.875rem;
background-color: white;
z-index: 999;
}
.fixed-header {
border-bottom: 1px solid black;
}
</style>
""",
unsafe_allow_html=True
)
This solution works for us as our app is for in-house use only thus we can guarantee everyone’s browsers is at the latest version and thus supports the has() pseudo class
Thanks a lot @zedfly, you just saved a bunch of my time.
I reworked a code a bit to make it more reusable. Maybe it can be useful for some of you future-visitors:
from typing import Literal
import streamlit as st
MARGINS = {
"top": "2.875rem",
"bottom": "0",
}
STICKY_CONTAINER_HTML = """
<style>
div[data-testid="stVerticalBlock"] div:has(div.fixed-header-{i}) {{
position: sticky;
{position}: {margin};
background-color: white;
z-index: 999;
}}
</style>
<div class='fixed-header-{i}'/>
""".strip()
# Not to apply the same style to multiple containers
count = 0
def sticky_container(
*,
height: int | None = None,
border: bool | None = None,
mode: Literal["top", "bottom"] = "top",
margin: str | None = None,
):
if margin is None:
margin = MARGINS[mode]
global count
html_code = STICKY_CONTAINER_HTML.format(position=mode, margin=margin, i=count)
count += 1
container = st.container(height=height, border=border)
container.markdown(html_code, unsafe_allow_html=True)
return container
if __name__ == "__main__":
st.title("Sticky Container")
st.write("This is a demonstration of a sticky container.")
for i in range(30):
st.write(f"Line {i}")
with sticky_container(mode="top", border=True):
st.write("This is a sticky container at the top.")
st.write("This is a sticky container at the top.")
for i in range(30):
st.write(f"Line {i}")
with sticky_container(mode="bottom", border=True):
st.write("This is a sticky container at the bottom.")
st.write("This is a sticky container at the bottom.")
for i in range(30):
st.write(f"Line {i}")
I reworked a code a bit in order to support both sticky/fixed positioning. Also, now it changes width as well as all other elements. And it updates background color if color-theme changes
with fixed_container(mode="fixed", position="bottom", border=True):
st.write("This is a fixed container.")
st.write("This is a fixed container.")
st.write("This is a fixed container.")
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.