building-streamlit-multipage-apps

Par streamlit · agent-skills

Créer des applications Streamlit multi-pages. À utiliser lors de la création d'applications avec plusieurs pages, la mise en place de la navigation ou la gestion de l'état entre les pages.

npx skills add https://github.com/streamlit/agent-skills --skill building-streamlit-multipage-apps

Applications Streamlit multi-pages

Structure et navigation pour les apps avec plusieurs pages.

Structure du répertoire

streamlit_app.py          # Point d'entrée principal
app_pages/
    home.py
    analytics.py
    settings.py

Important : Nommez votre répertoire de pages app_pages/ (et non pages/). L'utilisation de pages/ entre en conflit avec l'ancienne API de découverte automatique de Streamlit et peut causer des comportements inattendus.

Module principal

# streamlit_app.py
import streamlit as st

# Initialiser l'état global (partagé entre les pages)
if "api_client" not in st.session_state:
    st.session_state.api_client = init_api_client()

# Définir la navigation
page = st.navigation([
    st.Page("app_pages/home.py", title="Home", icon=":material/home:"),
    st.Page("app_pages/analytics.py", title="Analytics", icon=":material/bar_chart:"),
    st.Page("app_pages/settings.py", title="Settings", icon=":material/settings:"),
])

# L'interface au niveau de l'app s'exécute avant le contenu de la page
# Utile pour les éléments partagés comme les titres
st.title(f"{page.icon} {page.title}")

page.run()

Note : Quand vous gérez les titres dans streamlit_app.py, les pages individuelles ne doivent PAS utiliser st.title à nouveau.

Position de la navigation

Peu de pages (3-7) → Navigation en haut :

page = st.navigation([...], position="top")

Crée un menu horizontal épuré. Parfait pour les apps simples. Les sections sont supportées aussi—elles apparaissent comme des menus déroulants dans la nav du haut.

Nombreuses pages ou sections imbriquées → Sidebar :

page = st.navigation({
    "Main": [
        st.Page("app_pages/home.py", title="Home"),
        st.Page("app_pages/analytics.py", title="Analytics"),
    ],
    "Admin": [
        st.Page("app_pages/settings.py", title="Settings"),
        st.Page("app_pages/users.py", title="Users"),
    ],
}, position="sidebar")

Mixte : Certaines pages non groupées :

Utilisez une clé chaîne vide "" pour les pages qui ne doivent pas être dans une section. Ces pages non groupées apparaissent toujours en premier, avant tout groupe nommé. Mettez toutes les pages non groupées dans une seule clé "" :

page = st.navigation({
    "": [
        st.Page("app_pages/home.py", title="Home"),
        st.Page("app_pages/about.py", title="About"),
    ],
    "Analytics": [
        st.Page("app_pages/dashboard.py", title="Dashboard"),
        st.Page("app_pages/reports.py", title="Reports"),
    ],
}, position="top")

Modules de pages

# app_pages/analytics.py
import streamlit as st

# Accéder à l'état global
api = st.session_state.api_client
user = st.session_state.user

# Contenu spécifique à la page (le titre est géré dans streamlit_app.py)
data = api.fetch_analytics(user.id)
st.line_chart(data)

État global

Initialisez l'état dans le module principal seulement s'il est nécessaire sur plusieurs pages :

# streamlit_app.py
st.session_state.api = init_client()
st.session_state.user = get_user()
st.session_state.settings = load_settings()

Conseil : Utilisez st.session_state.setdefault("key", default_value) pour initialiser les valeurs seulement si elles n'existent pas.

Pourquoi le module principal (pour l'état global) :

  • S'exécute avant chaque page
  • Garantit que l'état est initialisé
  • Source unique de vérité

État spécifique à une page

Utilisez des clés préfixées pour l'état spécifique à une page :

# app_pages/analytics.py
if "analytics_date_range" not in st.session_state:
    st.session_state.analytics_date_range = default_range()

Partager des éléments entre les pages

Mettez l'interface partagée au point d'entrée (avant page.run()) pour qu'elle apparaisse sur toutes les pages :

# streamlit_app.py
import streamlit as st

pages = [...]
page = st.navigation(pages)

# Titre partagé
st.title(f"{page.icon} {page.title}")

# Widgets de sidebar partagés
with st.sidebar:
    st.selectbox("Theme", ["Light", "Dark"])

page.run()

Navigation programmatique

Naviguer vers une autre page par programme :

if st.button("Go to Settings"):
    st.switch_page("app_pages/settings.py")

Créer des liens de navigation avec st.page_link :

st.page_link("app_pages/home.py", label="Home", icon=":material/home:")
st.page_link("https://example.com", label="External", icon=":material/open_in_new:")

Note : Préférez st.navigation à st.page_link pour la navigation standard. N'utilisez pas st.page_link pour recréer la barre de nav que vous obtenez avec st.navigation. N'utilisez st.page_link que quand vous liez vers des pages depuis ailleurs que la sidebar, ou quand vous construisez un menu de navigation plus complexe.

Pages conditionnelles

Montrez différentes pages selon le rôle de l'utilisateur, l'authentification, ou toute autre condition en construisant la liste des pages dynamiquement :

# streamlit_app.py
import streamlit as st

pages = [st.Page("app_pages/home.py", title="Home", icon=":material/home:")]

if st.user.is_logged_in:
    pages.append(st.Page("app_pages/dashboard.py", title="Dashboard", icon=":material/bar_chart:"))

if st.session_state.get("is_admin"):
    pages.append(st.Page("app_pages/admin.py", title="Admin", icon=":material/settings:"))

page = st.navigation(pages)
page.run()

Conditions courantes pour afficher/masquer des pages :

  • st.user.is_logged_in pour les utilisateurs authentifiés
  • Flags st.session_state (rôles, permissions, feature flags)
  • Variables d'environnement ou secrets
  • Accès basé sur le temps (ex. : fonctionnalités bêta)

Imports depuis les pages

Quand vous importez depuis des fichiers de pages dans app_pages/, toujours importer depuis la perspective du répertoire racine :

# app_pages/dashboard.py - BON
from utils.data import load_sales_data

# app_pages/dashboard.py - MAUVAIS (n'utilisez pas d'imports relatifs)
from ..utils.data import load_sales_data

Références

Skills similaires