Agent skill
using-streamlit-layouts
Structuring Streamlit app layouts. Use when placing content in sidebars, columns, containers, or dialogs. Covers sidebar usage, column limits, horizontal containers, dialogs, and bordered cards.
Install this agent skill to your Project
npx add-skill https://github.com/streamlit/agent-skills/tree/main/developing-with-streamlit/skills/using-streamlit-layouts
SKILL.md
Streamlit layout
How you structure your app affects usability more than you think.
Sidebar: navigation + global filters only
The sidebar should only contain navigation and app-level filters. Main content goes in the main area.
# GOOD
with st.sidebar:
date_range = st.date_input("Date range")
region = st.selectbox("Region", ["All", "US", "EU", "APAC"])
st.caption("App v1.2.3")
# BAD: Too much content in sidebar
with st.sidebar:
st.title("Dashboard")
st.dataframe(df) # Don't put main content here
st.bar_chart(data)
What goes in sidebar:
- Global filters (date range, user selection, region)
- App info (version, feedback link)
What stays out:
- Main content, charts, tables, results
Columns: max 4, set alignment
Don't use too many columns—they get cramped.
# GOOD
col1, col2 = st.columns(2)
# Custom widths (ratios)
col1, col2 = st.columns([2, 1]) # 2:1 ratio
# OK with alignment
cols = st.columns(4, vertical_alignment="center")
# BAD: Too many, cramped
col1, col2, col3, col4, col5, col6 = st.columns(6)
Horizontal containers for button groups
Use st.container(horizontal=True) instead of columns for button groups:
with st.container(horizontal=True):
st.button("Cancel")
st.button("Save")
st.button("Submit")
Aligning elements
Use horizontal_alignment on containers to position elements:
# Center elements
with st.container(horizontal_alignment="center"):
st.image("logo.png", width=200)
st.title("Welcome")
# Right-align elements
with st.container(horizontal_alignment="right"):
st.button("Settings", icon=":material/settings:")
# Distribute evenly (great for button groups)
with st.container(horizontal=True, horizontal_alignment="distribute"):
st.button("Cancel")
st.button("Save")
st.button("Submit")
Options: "left" (default), "center", "right", "distribute"
Bordered containers
Use border=True on containers for visual grouping. See building-streamlit-dashboards for dashboard-specific patterns like KPI cards.
with st.container(border=True):
st.subheader("Section title")
st.write("Grouped content here")
Tabs
Organize content into switchable views:
tab1, tab2 = st.tabs(["Chart", "Data"])
with tab1:
st.line_chart(data)
with tab2:
st.dataframe(df)
Expander
Collapsible sections for secondary content:
with st.expander("See details"):
st.write("Hidden content here")
st.code("print('hello')")
Empty and placeholders
st.empty() creates a single-element placeholder that can be updated or cleared:
placeholder = st.empty()
# Update the placeholder
placeholder.text("Loading...")
result = load_data()
placeholder.dataframe(result)
# Clear it
placeholder.empty()
Popover
Click to reveal content:
with st.popover("Settings"):
st.checkbox("Dark mode")
st.slider("Font size", 10, 24)
Dialogs for focused interactions
Use @st.dialog for UI that doesn't need to be always visible:
@st.dialog("Confirm deletion")
def confirm_delete(item_name):
st.write(f"Are you sure you want to delete **{item_name}**?")
if st.button("Delete", type="primary"):
delete_item(item_name)
st.rerun()
if st.button("Delete item"):
confirm_delete("My Document")
Key points:
- Dialogs rerun independently from the main script
- Use
st.session_stateto pass widget values from the dialog to the main app - Call
st.rerun()to close dialog and refresh main app - Use
dismissible=Falsefor forced actions st.sidebaris not supported inside dialogs
When to use dialogs:
- Confirmation prompts
- Settings panels
- Forms that don't need to be always visible
Spacing
Control spacing between elements with gap on containers:
# Remove spacing for tight list-like UIs
with st.container(gap=None, border=True):
for item in items:
st.checkbox(item.text)
# Explicit gap sizes
with st.container(gap="small"):
...
Add vertical space with st.space:
st.space("small") # Small gap
st.space("medium") # Medium gap
st.space("large") # Large gap
st.space(50) # Custom pixels
Width and height
Control element sizing:
# Stretch to fill available space (equal height columns)
cols = st.columns(2)
with cols[0].container(border=True, height="stretch"):
st.line_chart(data)
with cols[1].container(border=True, height="stretch"):
st.dataframe(df)
# Shrink to content size
st.container(width="content")
# Fixed pixel sizes
st.container(height=300)
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
template-skill
Replace with description of the skill and when to use it.
developing-with-streamlit
**[REQUIRED]** Use for ALL Streamlit tasks: creating, editing, debugging, beautifying, styling, theming, optimizing, or deploying Streamlit applications. Also required for building custom components (inline or packaged), using st.components.v2, or any HTML/JS/CSS component work. Triggers: streamlit, st., dashboard, app.py, beautify, style, CSS, color, background, theme, button, widget styling, custom component, st.components, packaged component, pyproject.toml, asset_dir, CCv2, HTML/JS component.
organizing-streamlit-code
Organizing Streamlit code for maintainability. Use when structuring apps with separate modules and utilities. Covers separation of concerns, keeping UI code clean, and import patterns.
building-streamlit-chat-ui
Building chat interfaces in Streamlit. Use when creating conversational UIs, chatbots, or AI assistants. Covers st.chat_message, st.chat_input, message history, and streaming responses.
building-streamlit-multipage-apps
Building multi-page Streamlit apps. Use when creating apps with multiple pages, setting up navigation, or managing state across pages.
displaying-streamlit-data
Displaying charts, dataframes, and metrics in Streamlit. Use when visualizing data, configuring dataframe columns, or adding sparklines to metrics. Covers native charts, Altair, and column configuration.
Didn't find tool you were looking for?