lib/streamlit/.agents/skills/developing-with-streamlit/assets/templates/apps/README.md
This directory contains ready-to-use dashboard templates for Streamlit. Each template demonstrates best practices for building data-driven dashboards with modern UI patterns.
These templates are based on official Streamlit demo apps and work out of the box:
| Template | Description | Key Features |
|---|---|---|
| dashboard-seattle-weather | Weather data exploration dashboard | st.metric, st.pills, st.altair_chart, year comparison |
| dashboard-stock-peers | Stock peer analysis and comparison | st.multiselect, normalized charts, peer average calculation |
These templates demonstrate common dashboard patterns with synthetic data. Replace the data generation functions with your actual data sources:
| Template | Description | Key Features |
|---|---|---|
| dashboard-metrics | Core metrics dashboard with KPIs | Chart/table toggle, st.popover filters, TIME_RANGES (1M/6M/1Y/QTD/YTD/All) |
| dashboard-feature-usage | API endpoint usage analytics | Segmented control, starter kits, normalization toggle, rolling averages |
| dashboard-companies | Company leaderboard with drill-down | Interactive dataframe, sparkline columns, growth scores |
| dashboard-compute | Resource consumption monitoring | @st.fragment, st.popover filters, TIME_RANGES, line/bar toggle |
# Navigate to a template directory
cd assets/templates/apps/dashboard-metrics
# Sync dependencies from pyproject.toml
uv sync
# Run the app
uv run streamlit run streamlit_app.py
Each template follows this structure:
dashboard-{name}/
├── streamlit_app.py # Main application code
└── pyproject.toml # Dependencies and metadata
When creating new templates or adapting existing ones, follow these patterns for consistency.
Always set page config as the first Streamlit call, with layout="wide" and a Material icon:
st.set_page_config(
page_title="My Dashboard",
page_icon=":material/monitoring:",
layout="wide",
)
Use these standard constant names:
TIME_RANGES = ["1M", "6M", "1Y", "QTD", "YTD", "All"]
CHART_HEIGHT = 300 # Standard chart height in pixels
All dashboard templates that support time filtering use the same filter_by_time_range function:
def filter_by_time_range(df: pd.DataFrame, x_col: str, time_range: str) -> pd.DataFrame:
"""Filter dataframe by time range."""
if time_range == "All" or df.empty:
return df
df = df.copy()
df[x_col] = pd.to_datetime(df[x_col])
max_date = df[x_col].max()
if time_range == "1M":
min_date = max_date - timedelta(days=30)
elif time_range == "6M":
min_date = max_date - timedelta(days=180)
elif time_range == "1Y":
min_date = max_date - timedelta(days=365)
elif time_range == "QTD":
quarter_month = ((max_date.month - 1) // 3) * 3 + 1
min_date = pd.Timestamp(date(max_date.year, quarter_month, 1))
elif time_range == "YTD":
min_date = pd.Timestamp(date(max_date.year, 1, 1))
else:
return df
filtered: pd.DataFrame = df[df[x_col] >= min_date]
return filtered
Compact filter controls using st.popover:
with st.popover("Filters", type="tertiary"):
line_options = st.pills("Lines", ["Daily", "7-day MA"], selection_mode="multi")
time_range = st.segmented_control("Time range", TIME_RANGES, default="All")
def render_page_header(title: str):
"""Render page header with title and reset button."""
with st.container(
horizontal=True, horizontal_alignment="distribute", vertical_alignment="center"
):
st.markdown(title)
if st.button(":material/restart_alt: Reset", type="tertiary"):
st.session_state.clear()
st.rerun()
@st.fragment
def metric_card():
with st.container(border=True):
# This widget updates independently without full page rerun
...
@st.cache_data(ttl=3600)
def load_metric_data() -> pd.DataFrame:
"""Load metric data. Replace with your actual data source."""
# Replace this with:
# - API call
# - Database query
# - Data warehouse query via st.connection
return generate_synthetic_data()
All templates require Python >=3.10 and use:
streamlitaltair>=5.5.0pandas>=2.2.3numpy>=1.26.0 (most templates)