Layout: sidebar, columns, tabs and containers

Streamlit · Essentials · 10 min

A clear layout separates controls from results and keeps dense apps readable.

By default elements stack vertically in the main area. Layout primitives change that:

  • Sidebar: st.sidebar.selectbox(...), or with st.sidebar: for a block. Ideal for filters and settings.
  • Columns: left, right = st.columns(2) or relative widths st.columns([3, 1]); gap= and vertical_alignment= adjust spacing.
  • Tabs: tab1, tab2 = st.tabs(["Chart", "Data"]). All tabs' content is computed on each rerun, only display is switched, so expensive tabs still cost time.
  • Expander: with st.expander("Details"): hides secondary content.
  • Popover: with st.popover("Settings"): a button that opens a small floating panel.
  • Container: st.container(border=True) groups elements, and lets you write into a region later in the script: create it early, fill it later.
  • Placeholder: slot = st.empty() holds a single element you can replace, such as progress text updated in a loop.

Every layout object supports both styles: col.write(...) and with col: st.write(...).

st.set_page_config(page_title="Sales", page_icon="📈", layout="wide") sets the browser tab title and icon and switches to full-width layout; call it near the top of the script.

Nesting is allowed (columns inside tabs, containers in columns), but deep nesting gets cramped on small screens. Columns stack vertically on narrow mobile displays.

Example

import streamlit as st

st.set_page_config(page_title="Dashboard", layout="wide")

with st.sidebar:
    region = st.selectbox("Region", ["EU", "US", "APAC"])
    show_raw = st.toggle("Show raw data")

header = st.container()               # reserve space at the top, fill it later
left, right = st.columns([3, 1], vertical_alignment="center")
left.subheader(f"Sales in {region}")
right.metric("Orders", 1280, "+3%")

chart_tab, data_tab = st.tabs(["Chart", "Data"])
with chart_tab:
    st.bar_chart({"Q1": [10], "Q2": [14], "Q3": [12]})
with data_tab:
    if show_raw:
        st.write({"Q1": 10, "Q2": 14, "Q3": 12})

with st.expander("Methodology"):
    st.write("Orders are counted at shipping time.")
header.info(f"Filters: region={region}")   # appears above the columns

Remember

  • Sidebar for controls, columns and tabs for side-by-side or alternative views
  • Containers and st.empty() let you fill or replace regions later
  • st.set_page_config(layout='wide') uses the full browser width

Watch out for

  • Putting slow computations in a tab assuming they only run when the tab is opened; all tabs run every rerun.

Check yourself

  1. A dashboard has an expensive chart in the third tab. When is it computed?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.streamlit.io/develop/api-reference/layout