How to Build Streamlit Layouts with st.columns
Updated on
Streamlit columns are the main way to place elements side by side in a Streamlit app.
What Streamlit columns mean
If a Streamlit page feels too long, too linear, or too hard to scan, columns are often the first layout tool to reach for.
st.columns lets you split one horizontal section of the page into multiple containers. Each container can hold its own widgets, charts, metrics, tables, or explanatory text.
In plain terms, columns help a Streamlit app stop feeling like one long vertical notebook. They let you arrange related information next to each other so the user can compare, act, or understand faster.
Why st.columns matters
Columns matter because layout changes how quickly a reader understands the page.
The same data can feel:
- cluttered in one long column
- clear when metrics, controls, and outputs are grouped side by side
That is why columns often improve not just appearance, but also usability.
In real apps, they help with:
- dashboard-style summaries
- side-by-side comparisons
- form and output layouts
- action rows with buttons
- file upload plus preview flows
What st.columns is actually for
The point of columns is not to make the page "fancier." The point is to organize attention.
Use columns when you want the user to:
- compare two charts or two tables
- see filters beside results
- scan several metrics in one row
- keep related actions grouped together
After reading this guide, you should be able to:
- build simple and weighted column layouts
- use modern column options such as
gap,vertical_alignment,border, andwidth - choose between columns, sidebar, tabs, and containers more confidently
- avoid the most common layout mistakes in Streamlit
Quick Start
This first example shows the basic idea: create columns, then place content inside each one.
import streamlit as st
col1, col2 = st.columns(2)
with col1:
st.metric("Revenue", "$128K")
with col2:
st.metric("Growth", "12.4%")This is the most common use case for st.columns: putting related items on one row instead of stacking them vertically.
Use width ratios when the content is uneven
Not every layout should use equal-width columns. If one side needs more space, pass a list of ratios.
import streamlit as st
chart_col, notes_col = st.columns([3, 1])
with chart_col:
st.write("Main chart area")
with notes_col:
st.write("Key notes and filters")That pattern is useful when one column holds a chart or dataframe and the other holds lighter supporting content.
Core arguments you should know
| Argument | What it does | When to care |
|---|---|---|
spec | Sets the number of columns or their relative widths | Always |
gap | Controls the space between columns | Useful for density and readability |
vertical_alignment | Aligns content to the top, center, or bottom | Helpful for mixed-height content |
border | Adds borders around columns | Useful for card-like sections |
width | Controls the overall row width | Helpful in constrained layouts |
A modern st.columns example
This example uses current layout options to build a cleaner action-and-results row.
import streamlit as st
col1, col2 = st.columns(
[1, 2],
gap="medium",
vertical_alignment="top",
border=True,
)
with col1:
st.subheader("Controls")
st.selectbox("Region", ["APAC", "EMEA", "LATAM", "North America"])
st.button("Refresh", type="primary", width="stretch")
with col2:
st.subheader("Results")
st.write("Place your chart, table, or summary here")This kind of layout works well because it separates "decide" from "review" without forcing the user to scroll up and down.
Common column patterns in real apps
Metrics row
Columns are often the easiest way to show a small dashboard summary at the top of a page.
import streamlit as st
col1, col2, col3 = st.columns(3, gap="small")
with col1:
st.metric("Orders", "1,245")
with col2:
st.metric("Conversion", "5.2%")
with col3:
st.metric("Refund rate", "1.1%")Upload plus preview
This pattern is useful when users should provide a file and immediately see what was loaded.
import pandas as pd
import streamlit as st
upload_col, preview_col = st.columns([1, 2], gap="medium")
with upload_col:
uploaded_file = st.file_uploader("Upload CSV", type=["csv"])
with preview_col:
if uploaded_file is not None:
df = pd.read_csv(uploaded_file)
st.dataframe(df.head(), width="stretch")This is a common pattern for internal tools because it keeps the input and the feedback in one visual unit.
Controls beside results
If filters should stay visible while the user reads the output, a two-column layout is often more comfortable than pushing controls above a long result block.
That pattern works especially well when the right side contains a st.dataframe, chart, or summary card.
Layout plus exploratory analytics
If the real goal is not just "put two things side by side" but "put controls beside a rich exploratory data surface," PyGWalker can fit naturally into a Streamlit layout.
For example, one column can hold filters and notes, while the other holds a PyGWalker exploration view for the current dataframe.
See:
Action rows
If the page has paired actions such as Back/Next or Cancel/Save, columns give those actions a clean, predictable structure.
This is especially helpful when combined with st.button and st.session_state.
Columns vs other Streamlit layout tools
| Need | Better tool |
|---|---|
| Put elements side by side in the main page | st.columns |
| Keep global controls separate from the main page | st.sidebar |
| Group several elements without changing horizontal layout | st.container |
| Split large areas of content into switchable sections | st.tabs |
Columns are the right answer when the user benefits from seeing multiple things at once.
Practical layout advice
Keep the row simple
Two or three columns are usually easier to read than a row packed with many narrow sections.
Match layout to task complexity
If the content is dense or text-heavy, a single column may still be the better choice. Layout should help the content, not fight it.
Avoid deep nesting
Streamlit recommends not nesting columns more than once. In practice, deeper nesting usually makes the layout brittle and harder to read.
Use columns for comparison, not decoration
The strongest use cases are comparison, workflow grouping, and scannability. If the layout does not improve understanding, a simpler structure is usually better.
Troubleshooting
Why do my columns feel too cramped?
You may have too many columns for the amount of content on the page. Reduce the number of columns, widen the main one with ratios, or move global controls to the sidebar.
How do I align widgets that have different heights?
Use vertical_alignment when creating the columns, and keep the content inside each column structurally similar where possible.
Can I put buttons, uploads, and charts inside columns?
Yes. Columns are just containers, so they work with widgets, charts, text, tables, and media.
Why does nested layout become hard to manage?
Because each extra nesting level makes the page harder to reason about and more fragile on smaller screens. Keep nesting shallow.
Related Guides
Frequently Asked Questions
What does st.columns do in simple terms?
It creates side-by-side containers so you can place Streamlit elements on the same row.
How do I make one Streamlit column wider than another?
Pass a list of relative widths, such as st.columns([3, 1]).
When should I use columns in Streamlit?
Use columns when the user should compare items side by side or keep controls and results visible together.
How do I build a Streamlit layout?
Use layout primitives such as st.columns, st.sidebar, st.container, and st.tabs. st.columns is usually the main tool when the layout needs side-by-side sections.
Can I put widgets inside Streamlit columns?
Yes. You can place widgets, charts, text, metrics, and tables inside each column.
Should I nest Streamlit columns deeply?
Usually no. Streamlit recommends keeping nesting shallow because deep nesting makes layouts harder to manage and read.