lib/streamlit/.agents/skills/developing-with-streamlit/references/design.md
Small touches that make apps feel polished.
Visual design works hand-in-hand with other references:
selection-widgets.md — Choosing the right widget (segmented control, pills, toggle)data-display.md — Column config, sparklines, bordered metricslayouts.md — Containers, alignment, dashboard cardsSet browser tab title, icon, and layout. Place this at the top of your script to avoid visual blinking:
st.set_page_config(
page_title="My Dashboard",
page_icon=":material/analytics:",
layout="wide", # Use "wide" for dashboards with lots of data
)
Layout options:
layout="centered" (default) → Best for most apps, content is constrained to a readable widthlayout="wide" → Full-width, good for dashboards and data-heavy appsAdd a logo to the sidebar/header:
st.logo("logo.png")
Use Material Symbols for a cleaner, more professional look. Streamlit uses the Material Symbols icon set (not the older Material Icons).
# GOOD: Material Symbols
st.markdown(":material/settings:")
st.markdown(":material/calendar_today:")
st.markdown(":material/dashboard:")
st.markdown(":material/person:")
# SPARINGLY: Emojis for special occasions
st.markdown("Celebration! 🎉")
Format: :material/icon_name:
Find icons: https://fonts.google.com/icons
Popular icons by category:
| Category | Icons |
|---|---|
| Navigation | home, arrow_back, menu, settings, search |
| Actions | send, play_arrow, refresh, download, upload, save, delete, edit |
| Status | check_circle, error, warning, info, pending |
| Data | table_chart, bar_chart, analytics, query_stats, database |
| Content | chat, code, description, article, folder |
| UI | visibility, build, tune, filter_list |
For standalone badges:
st.badge("Active", icon=":material/check:", color="green")
st.badge("Pending", icon=":material/schedule:", color="orange")
st.badge("Deprecated", color="red")
For inline badges in text:
st.markdown("""
:green-badge[Active] :orange-badge[Pending] :red-badge[Deprecated] :blue-badge[New]
""")
Avoid the old verbose syntax:
# OLD (still works but cluttered)
st.markdown(":orange-background[:orange[Pending]]")
Dividers (st.divider() or ---) look heavy. Just remove them—Streamlit's default spacing is usually enough.
# BAD
st.header("Section 1")
st.write("Content")
st.divider() # Too heavy
st.header("Section 2")
# GOOD
st.header("Section 1")
st.write("Content")
st.header("Section 2")
If you genuinely need spacing:
st.space("small") # Small gap
st.space("medium") # Medium gap
st.space("large") # Large gap
st.space(50) # Custom pixels for fine-tuning
Don't systematically replace dividers with st.space()—it can look weird too.
Use sentence casing for titles and labels. Title Case Feels Shouty.
# GOOD
st.title("Upload your data")
st.selectbox("Select a region", options)
st.button("Save changes")
# BAD
st.title("Upload Your Data")
st.selectbox("Select A Region", options)
st.info() is too heavy for simple informational text.
# GOOD: Lighter
st.caption("Data last updated 5 minutes ago")
# BAD: Too heavy
st.info("Data last updated 5 minutes ago")
When to use what:
st.caption → Simple info, metadata, timestampsst.info → Important instructionsst.warning → Caution, potential issuesst.error → Errors that block progressst.success → Confirmation of actionst.toast → Lightweight confirmation that auto-dismissesUse text_alignment for text elements:
st.title("Centered title", text_alignment="center")
st.write("Right aligned", text_alignment="right")
st.caption("Justified text", text_alignment="justify")
Options: "left" (default), "center", "right", "justify"
Note: horizontal_alignment on containers positions elements but also sets their text_alignment. If you need different text alignment within a horizontally-aligned container, override text_alignment on the text element itself.
Material Symbols can make callouts and expanders look nicer:
st.info("Processing complete", icon=":material/check_circle:")
st.warning("Rate limit approaching", icon=":material/warning:")
st.error("Connection failed", icon=":material/error:")
st.success("Saved!", icon=":material/thumb_up:")
with st.expander("Settings", icon=":material/settings:"):
st.write("Configure your preferences")
Other elements like st.button and st.tabs also support icons—worth considering when it adds clarity.