st.sidebar: panel de control lateral
El sidebar es una columna lateral que aparece a la izquierda de la pantalla y constituye uno de los elementos de layout más importantes en Streamlit. Funciona como un panel de control persistente donde se ubican filtros globales, configuraciones y navegación que afectan al contenido principal de la aplicación.
La separación entre sidebar y contenido principal permite al usuario configurar los parámetros del análisis sin que los controles interfieran con los resultados visualizados. Cualquier widget de Streamlit puede colocarse en el sidebar usando dos sintaxis equivalentes:
import streamlit as st
import pandas as pd
import numpy as np
# Forma 1: Notación de punto (concisa)
st.sidebar.title("Configuración")
dataset = st.sidebar.selectbox("Dataset", ["Iris", "Tips", "Titanic"])
n_muestras = st.sidebar.slider("Muestras a mostrar", 10, 200, 50)
# Forma 2: Bloque with (recomendado para múltiples elementos)
with st.sidebar:
st.header("Filtros")
fecha_inicio = st.date_input("Desde")
fecha_fin = st.date_input("Hasta")
st.divider()
st.header("Visualización")
tipo_grafico = st.radio("Tipo de gráfico", ["Líneas", "Barras", "Área"])
mostrar_tabla = st.checkbox("Mostrar tabla de datos", value=True)
# Contenido principal
st.title("Dashboard de análisis")
st.write(f"Dataset: **{dataset}** | Muestras: **{n_muestras}**")
flowchart LR
A[Página Streamlit] --> B[Área principal central]
A --> C[st.sidebar lateral izquierdo]
C --> D[Filtros globales]
C --> E[Configuración modelo]
C --> F[Navegación multipagina]
D --> G[Cambia parámetros]
E --> G
F --> H[Salta a otra página .py]
G --> I[Rerun completo del script]
I --> J[Área principal recalcula resultados]
H --> K[Streamlit cambia página activa]
A -.->|initial_sidebar_state| L[expanded collapsed auto]
Configuración del sidebar en st.set_page_config
El estado inicial del sidebar se controla globalmente con st.set_page_config, que debe ser la primera llamada a Streamlit en el script:
import streamlit as st
st.set_page_config(
page_title="Mi Dashboard",
initial_sidebar_state="expanded" # "auto", "expanded", "collapsed"
)
Los tres valores de initial_sidebar_state cubren diferentes necesidades:
"auto"(predeterminado): detecta automáticamente si el sidebar debe mostrarse según el espacio disponible en pantalla. En escritorio se abre; en móvil se cierra."expanded": siempre muestra el sidebar abierto al cargar la aplicación, independientemente del dispositivo."collapsed": muestra el sidebar cerrado inicialmente. El usuario puede abrirlo pulsando el icono de hamburguesa en la esquina superior izquierda.
Sidebar con formulario de filtros
import streamlit as st
import pandas as pd
import numpy as np
@st.cache_data
def cargar_datos():
np.random.seed(42)
return pd.DataFrame({
"region": np.random.choice(["Norte", "Sur", "Este", "Oeste"], 500),
"producto": np.random.choice(["A", "B", "C", "D"], 500),
"ventas": np.random.randint(100, 5000, 500),
"año": np.random.choice([2024, 2025, 2026], 500)
})
df = cargar_datos()
with st.sidebar:
st.header("Filtros globales")
st.caption("Los filtros se aplican a todos los gráficos y tablas.")
# Usar formulario para aplicar todos los filtros de una vez
with st.form("filtros_form"):
regiones = st.multiselect("Regiones", df["region"].unique(), default=list(df["region"].unique()))
productos = st.multiselect("Productos", df["producto"].unique(), default=list(df["producto"].unique()))
años = st.pills("Año", sorted(df["año"].unique()), selection_mode="multi")
aplicar = st.form_submit_button("Aplicar filtros", type="primary", use_container_width=True)
st.divider()
st.caption(f"Total registros sin filtrar: {len(df):,}")
# Aplicar filtros
if aplicar:
df_filtrado = df[
df["region"].isin(regiones) &
df["producto"].isin(productos) &
(df["año"].isin(años) if años else True)
]
else:
df_filtrado = df
# Contenido principal
st.title("Dashboard de ventas")
st.write(f"Mostrando **{len(df_filtrado):,}** de {len(df):,} registros.")
col1, col2 = st.columns(2)
with col1:
st.bar_chart(df_filtrado.groupby("region")["ventas"].sum())
with col2:
st.bar_chart(df_filtrado.groupby("producto")["ventas"].sum())
Información de sesión en el sidebar
import streamlit as st
from datetime import datetime
with st.sidebar:
# Logo de la aplicación
st.image("https://streamlit.io/images/brand/streamlit-logo-secondary-colormark-darktext.png", width=200)
st.divider()
# Filtros principales
st.header("Configuración")
vista = st.selectbox("Vista", ["Diaria", "Semanal", "Mensual"])
st.divider()
# Información de la sesión al final del sidebar
st.caption(f"Última actualización: {datetime.now().strftime('%d/%m/%Y %H:%M')}")
st.caption("Versión 2.4.1 | CertiDevs 2026")
if st.button("Cerrar sesión", use_container_width=True):
st.warning("Sesión cerrada.")
st.stop()
Sidebar con múltiples secciones organizadas
import streamlit as st
with st.sidebar:
st.title("Panel de control")
# Sección 1: Datos
with st.expander("📂 Fuente de datos", expanded=True):
fuente = st.radio("", ["Base de datos", "Archivo CSV", "API REST"])
if fuente == "Base de datos":
bd = st.selectbox("Base de datos", ["Producción", "Staging", "Desarrollo"])
# Sección 2: Análisis
with st.expander("🔬 Análisis", expanded=True):
modelo = st.selectbox("Modelo", ["RF", "XGB", "SVM"])
umbral = st.slider("Umbral de decisión", 0.0, 1.0, 0.5)
usar_pca = st.toggle("Reducción PCA")
# Sección 3: Visualización
with st.expander("🎨 Visualización"):
tema = st.radio("Tema de gráficos", ["Claro", "Oscuro", "Automático"])
color = st.color_picker("Color principal", "#FF4B4B")
densidad = st.slider("Puntos en scatter", 50, 2000, 500)
La regla práctica para decidir qué va en el sidebar es: todo lo que se configura una vez por sesión (filtros globales, fuente de datos, parámetros de modelo) va al sidebar, mientras que lo que cambia frecuentemente durante el uso (paginación, selección de registros, acciones puntuales) va en el contenido principal.
En aplicaciones multipágina, el sidebar se mantiene visible en todas las páginas, lo que permite compartir filtros globales sin necesidad de duplicar los widgets en cada vista. Esto se gestiona automáticamente cuando los valores se almacenan en
st.session_state.
Contexto: el rol del sidebar en la experiencia de usuario
El patrón de sidebar + área principal es una convención extendida en dashboards profesionales desde hace décadas. Tableau, Power BI, Kibana, Superset... todos usan este mismo modelo porque responde a una necesidad psicológica del usuario: separar visualmente los controles de los resultados. Cuando ambos ocupan el mismo espacio, la interfaz se percibe como desordenada y el usuario pierde tiempo buscando el widget que necesita.
En Streamlit, el sidebar no solo es un contenedor más: está integrado en el diseño responsive de la app. En móviles se colapsa automáticamente, en escritorio ocupa un 20 % del ancho aproximadamente, y en tablets se adapta al espacio disponible. Además, todos los widgets dentro del sidebar se sincronizan con st.session_state exactamente igual que los del área principal, por lo que puedes compartir filtros globales entre páginas en aplicaciones multipágina sin esfuerzo adicional.
Explicación línea por línea del formulario de filtros
En el ejemplo del dashboard con filtros globales se combinan varias técnicas importantes:
@st.cache_dataevita regenerar el DataFrame en cada rerun: el cálculo se hace una sola vez por sesión.with st.sidebar:abre un contexto donde todos los widgets irán al panel lateral.- El
st.form("filtros_form")agrupa los multiselects y el botón: los cambios no se aplican hasta que el usuario pulsa "Aplicar filtros", evitando reruns intermedios por cada ajuste. df["region"].isin(regiones) & df["producto"].isin(productos)usa máscaras booleanas de pandas para filtrar por múltiples condiciones en una sola expresión.- El contenido principal queda limpio: solo muestra el resultado de los filtros sin saturar al usuario con widgets de configuración.
Tabla de parámetros relacionados
| Parámetro | Contexto | Descripción |
|-----------|----------|-------------|
| initial_sidebar_state | st.set_page_config | "auto", "expanded" o "collapsed" |
| layout | st.set_page_config | "centered" o "wide" (afecta al área principal pero impacta el sidebar) |
| st.sidebar.title/header/etc. | todos | Cualquier widget de Streamlit es válido |
| key | widgets dentro del sidebar | Identificador único para session_state |
Errores comunes
Colocar st.set_page_config después de otro widget. Debe ser la primera llamada a Streamlit en el script. Si la colocas después de un st.write, Streamlit lanzará un error.
Sidebar demasiado largo. Si metes demasiados widgets, el usuario tendrá que hacer scroll dentro del sidebar para llegar a los controles del final. Agrupa con st.expander y esconde la configuración avanzada.
Duplicar widgets en cada página multipágina. En apps con st.navigation, no repliques los mismos filtros en cada archivo de página: colócalos una sola vez en st.sidebar desde el script principal y serán visibles en todas las páginas.
Forzar sidebar abierto en móvil. Usar initial_sidebar_state="expanded" en móvil es molesto: ocupa prácticamente toda la pantalla. Prefiere "auto" salvo que tengas una razón específica.
Mejores prácticas
- Usa secciones con
st.headeryst.dividerpara dar estructura visual al sidebar. - Coloca los filtros más usados al principio y los avanzados dentro de
st.expander. - Incluye un pie con información contextual (versión, última actualización, usuario logueado) usando
st.caption. - Para formularios complejos en el sidebar, combina siempre con
st.formpara reducir reruns innecesarios. - Si necesitas ocultar completamente el sidebar en una página concreta, considera usar CSS inyectado con
st.htmlo cambiar a un layout sin sidebar para esa vista.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Streamlit es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Streamlit
Explora más contenido relacionado con Streamlit y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Añadir cualquier widget al sidebar con st.sidebar.widget() o el bloque with st.sidebar. Organizar el sidebar con secciones, divisores y jerarquía visual. Controlar el estado inicial del sidebar con initial_sidebar_state. Usar el sidebar para filtros globales que afectan a toda la aplicación. Combinar sidebar con session_state para persistir configuraciones.