Streamlit Floating Container
A Streamlit custom component that creates a floating, draggable panel overlay for your Streamlit applications. Perfect for adding chat interfaces, FAQ sections, or any content that needs to be accessible without leaving the current page.
Features
- Floating Panel — a glassmorphic floating panel that hovers over your Streamlit app
- Draggable — vertical drag handle to reposition the panel button anywhere on the screen
- Expandable — toggle the panel to nearly full viewport height
- Start Position — configure the initial button position (top, middle, or bottom)
- Auto-pinned Chat Input —
st.chat_inputplaced directly inside the container automatically sticks to the bottom, mimicking Streamlit's native chat layout - Customizable — Material icon support, optional label, and glassmorphic toggle
- Theme Integration — automatically adapts to your Streamlit theme colors
- Resilient to reruns — component hot-updates in place from props; DOM state survives Streamlit reruns without reload hacks
Installation
pip install streamlit-floating-container
Using UV:
uv add streamlit-floating-container
Usage
import streamlit as st
from streamlit_floating_container import FloatingContainer
st.set_page_config(layout="wide")
st.title("My App")
fp = FloatingContainer(
icon=":material/chat:",
label="Help",
start_position="top",
key="my_float",
glassmorphic=True,
)
with fp.panel():
st.subheader("FAQ", anchor=False)
st.write("Your content here...")
Chat Example
Place st.chat_input directly inside the container — the component
auto-pins it to the bottom of the panel (via the has-chat class on the
scrollable wrapper) so it behaves like Streamlit's native chat layout.
import streamlit as st
from streamlit_floating_container import FloatingContainer
st.set_page_config(layout="wide")
st.title("My App")
if "chats" not in st.session_state:
st.session_state["chats"] = []
def submit_chat(stkey):
st.session_state["chats"].append(
dict(who="user", message=st.session_state[stkey])
)
st.session_state["chats"].append(
dict(who="ai", message="Response message")
)
fp = FloatingContainer(
icon=":material/chat:",
label="Chat",
start_position="middle",
key="chat_float",
)
with fp.panel():
# Message history
for chat in st.session_state["chats"]:
with st.chat_message(chat.get("who")):
st.write(chat.get("message"))
# Chat input placed directly in the container —
# auto-pinned to the bottom of the panel.
st.chat_input(
"Type a message...",
key="chat_input",
on_submit=submit_chat,
args=["chat_input"],
)
Note: Only one
st.chat_inputwidget is allowed per floating container. Additional chat inputs trigger a console warning and the panel will visually anchor the first one it finds.
FAQ / Static Content Example
import streamlit as st
from streamlit_floating_container import FloatingContainer
fp = FloatingContainer(
icon=":material/help:",
label="FAQ",
start_position="bottom",
key="faq",
glassmorphic=False, # solid background instead of frosted glass
)
with fp.panel():
st.subheader("Frequently Asked Questions", anchor=False)
st.markdown("**Q: How do I reset my password?**")
st.markdown("A: Visit your profile page and click *Reset*.")
st.divider()
st.markdown("**Q: Who do I contact for support?**")
st.markdown("A: Email support@example.com.")
API Reference
FloatingContainer
FloatingContainer(
icon: str,
label: str = "",
start_position: Literal["top", "middle", "bottom"] = "top",
key: str = "",
glassmorphic: bool = True,
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
icon |
str |
required | Material icon (e.g., :material/chat:) or single character |
label |
str |
"" |
Label displayed in the panel header |
start_position |
str |
"top" |
Initial button position: "top" (8%), "middle" (40%), or "bottom" (84%) |
key |
str |
"" |
Unique key for the component instance |
glassmorphic |
bool |
True |
Enable the frosted-glass / blur panel style |
Only one FloatingContainer instance may be mounted per page. Attempting
to mount a second one raises RuntimeError.
panel() context manager
with fp.panel():
st.write("This appears in the floating panel")
panel() enters the panel's scrollable container directly — anything
you render inside the with block appears in the floating panel. You
do not need a second nested with statement.
If you render a st.chat_input(...) inside the panel, the component
automatically pins it to the bottom. No manual placement required.
Panel Controls
| Control | Description |
|---|---|
| Open Button | Click the floating button to open the panel |
| Close Button | X button in the top-right corner |
| Expand / Collapse | Toggle between normal size and near-fullscreen |
| Stretch Width | Toggle the panel width between the default (400px) and stretched (800px) |
| Drag Handle | Appears on hover on the floating button — drag vertically to reposition |
Styling
The component uses CSS variables from your Streamlit theme:
--st-primary-color— button and accent colors--st-secondary-background-color— drag handle background, pinned chat-input background--st-text-color— text and icon colors
The panel features a glassmorphic design with blur effects and subtle
shadows when glassmorphic=True. Set glassmorphic=False for a solid
background that matches the theme.
Classes applied at runtime
| Class | Target | Added when |
|---|---|---|
panel-open |
#floating-panel, #close-panel |
Panel is open |
expanded |
#floating-panel |
Panel is in expanded (near-fullscreen) mode |
glassmorphic |
#floating-panel |
glassmorphic=True |
has-chat |
#panel-scrollable |
A chat input is present in the container |
scrollable-panel-is-empty |
#panel-scrollable |
No elements present |
empty |
#input-div |
No elements in the fixed bottom slot |
nav-open |
#open-panel |
Panel is open (used to hide the toggle button) |
hidden |
#drag-handle |
Panel is open (hide drag handle) |
active |
#movable-wrapper |
User is dragging the button |
Implementation Notes
- CCv2 component. Built on
st.components.v2.component— the component is registered once at module import and mounted per render. - No reload handshake. The component hot-updates from
dataon every render; no full-page reload orlocalStorageprop diff. - DOM safety. Streamlit-managed nodes are never moved between trees;
the component only toggles classes on them, avoiding React reconciler
crashes (
NotFoundError: insertBefore/removeChild) on reruns. - Observers. A
MutationObserverwatches the scrollable area to keep thehas-chatclass in sync with the actual presence of a chat input, across reruns and conditional renders. - Single-instance invariant. Mounting more than one
FloatingContainerper page raisesRuntimeErrorfrom Python.
File Structure
streamlit-floating-container/
├── pyproject.toml
├── README.md
└── streamlit_floating_container/
├── __init__.py
├── floating_container.html
├── floating_container.js
└── styles.css
Development
git clone https://github.com/your-username/streamlit-floating-container.git
cd streamlit-floating-container
pip install -e .
Then run any demo script (e.g., main.py) with Streamlit:
streamlit run main.py
License
MIT
Metadata
Release files for streamlit-floating-container 0.2.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| streamlit_floating_container-0.2.7.tar.gz | 54.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| streamlit_floating_container-0.2.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.7 kB
Release files / streamlit_floating_container-0.2.7.tar.gz
| Download URL | streamlit_floating_container-0.2.7.tar.gz |
|---|---|
| Size | 54.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
92100c7e92be77e34bf0db50eebe6362a981b7be1552c964d5ed377ab420d5cd
|
|
BLAKE2b-256 checksum How to use checksums |
f684a2d7408458d733fdac99c97403bde94caed77b12c309da33511a1b9b9f07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / streamlit_floating_container-0.2.7-py3-none-any.whl
| Download URL | streamlit_floating_container-0.2.7-py3-none-any.whl |
|---|---|
| Size | 12.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4afbea709e018eaafaf6eaf1afed27fa5ceec26c8444770d595c8cbe2474328
|
|
BLAKE2b-256 checksum How to use checksums |
5f92042d7d012446053e62ecb44f049187255520be435ab2a77243fb800a353c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for streamlit-floating-container 0.2.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.