Skip to main content

Streamlit Multipage

Simple Python package to implement multiple pages using streamlit.

pip install streamlit-multipage

Getting started

Simple single-page app

Given one streamlit app in a Python file like this:

import streamlit as st

st.title("My Amazing App")
name = st.text_input("Your Name: ")
st.write(f"Hello {name}!")

Wrap it into a function with a st parameter and arbitrary keyword arguments.

import streamlit as st
from streamlit_multipage import MultiPage


def my_page(st, **state):
    st.title("My Amazing App")
    name = st.text_input("Your Name: ")
    st.write(f"Hello {name}!")


app = MultiPage()
app.st = st

app.add_app("Hello World", my_page)

app.run()

This example is trivial and will not give any additional value. The next example will introduce state persistance.

Saving State

If the state should be persisted between re-runs (pressing R) o application runs (running streamlit run). The variables can be saved by calling the save function and accessed conveniently via the state dictionary.

import streamlit as st
from streamlit_multipage import MultiPage


def my_page(st, **state):
    st.title("My Amazing App")
    name_ = state["name"] if "name" in state else ""
    name = st.text_input("Your Name: ", value=name_)
    st.write(f"Hello {name}!")

    MultiPage.save({"name": name})


app = MultiPage()
app.st = st

app.add_app("Hello World", my_page)

app.run()

Multiple pages

When dealing with multiple pages, the workflow is the same. If reading, always sanitize the input and make sure the values are available and correct.

import streamlit as st
from streamlit_multipage import MultiPage


def input_page(st, **state):
    st.title("Body Mass Index")

    weight_ = state["weight"] if "weight" in state else 0.0
    weight = st.number_input("Your weight (Kg): ", value=weight_)

    height_ = state["height"] if "height" in state else 0.0
    height = st.number_input("Your height (m): ", value=height_)

    if height and weight:
        MultiPage.save({"weight": weight, "height": height})


def compute_page(st, **state):
    st.title("Body Mass Index")

    if "weight" not in state or "height" not in state:
        st.warning("Enter your data before computing. Go to the Input Page")
        return

    weight = state["weight"]
    height = state["height"]

    st.metric("BMI", round(weight / height ** 2, 2))


app = MultiPage()
app.st = st

app.add_app("Input Page", input_page)
app.add_app("BMI Result", compute_page)

app.run()

Using Namespaces

When handling multiple pages, it is possible to have variable name collisions, by default all variables are saved in a common namespace called global but it is also possible to defined custom namepsaces. One page can write to many namespaces at once.

import streamlit as st
from streamlit_multipage import MultiPage


def input_page(st, **state):
    namespace = "input"
    variables = state[namespace] if namespace in state else {}
    st.title("Tax Deduction")

    salary_ = variables["salary"] if "salary" in variables else 0.0
    salary = st.number_input("Your salary (USD): ", value=salary_)

    tax_percent_ = variables["tax_percent"] if "tax_percent" in variables else 0.0
    tax_percent = st.number_input("Taxes (%): ", value=tax_percent_)

    total = salary * (1 - tax_percent)

    if tax_percent and salary:
        MultiPage.save({"salary": salary, "tax_percent": tax_percent}, namespaces=[namespace])

    if total:
        MultiPage.save({"total": total}, namespaces=[namespace, "result"])


def compute_page(st, **state):
    namespace = "result"
    variables = state[namespace] if namespace in state else {}
    st.title("Your Salary After Taxes")

    if "total" not in variables:
        st.warning("Enter your data before computing. Go to the Input Page")
        return

    total = variables["total"]

    st.metric("Total", round(total, 2))


app = MultiPage()
app.st = st

app.add_app("Input Page", input_page)
app.add_app("Net Salary", compute_page)

app.run()

Automatic Namespaces

If the namespace is set to the same App name (first parameter of add_app) the state will be pre-filtered before sending it to the function.

import streamlit as st
from streamlit_multipage import MultiPage


def input_page(st, **state):
    st.title("Tax Deduction")

    salary_ = state["salary"] if "salary" in state else 0.0
    salary = st.number_input("Your salary (USD): ", value=salary_)

    tax_percent_ = state["tax_percent"] if "tax_percent" in state else 0.0
    tax_percent = st.number_input("Taxes (%): ", value=tax_percent_)

    total = salary * (1 - tax_percent)

    if tax_percent and salary:
        MultiPage.save({"salary": salary, "tax_percent": tax_percent}, namespaces=["Input Page"])

    if total:
        MultiPage.save({"total": total}, namespaces=["Net Salary"])


def compute_page(st, **state):
    st.title("Your Salary After Taxes")

    if "total" not in state:
        st.warning("Enter your data before computing. Go to the Input Page")
        return

    total = state["total"]

    st.metric("Total", round(total, 2))


app = MultiPage()
app.st = st

app.add_app("Input Page", input_page)
app.add_app("Net Salary", compute_page)

app.run()

Directory Structure

When dealing with multiple, complex pages, it is not convenient to have them all in a single .py file. This example shows how to lay out the directory structure to have an organize project.

.
└── root/
    ├── pages/
    │   ├── __init__.py
    │   ├── input_data.py
    │   └── result.py
    └── main.py/

input_data.py

from streamlit_multipage import MultiPage


def input_page(st, **state):
    st.title("Tax Deduction")

    salary_ = state["salary"] if "salary" in state else 0.0
    salary = st.number_input("Your salary (USD): ", value=salary_)

    tax_percent_ = state["tax_percent"] if "tax_percent" in state else 0.0
    tax_percent = st.number_input("Taxes (%): ", value=tax_percent_)

    total = salary * (1 - tax_percent)

    if tax_percent and salary:
        MultiPage.save({"salary": salary, "tax_percent": tax_percent}, namespaces=["Input Page"])

    if total:
        MultiPage.save({"total": total}, namespaces=["Net Salary"])

Result.py

def compute_page(st, **state):
    st.title("Your Salary After Taxes")

    if "total" not in state:
        st.warning("Enter your data before computing. Go to the Input Page")
        return

    total = state["total"]

    st.metric("Total", round(total, 2))

__init__.py

from .input_data import input_page
from .result import compute_page

pages = {
    "Input Page": input_page,
    "Net Salary": compute_page,
}

main.py

from pages import pages

import streamlit as st
from streamlit_multipage import MultiPage


app = MultiPage()
app.st = st

for app_name, app_function in pages.items():
    app.add_app(app_name, app_function)

app.run()

Landing Page

In is also possible to show a landing page that will be show only on start up and then redirect to the main app. The landing page is merely informative and has no access to the state.

import streamlit as st
from streamlit_multipage import MultiPage, save


def input_page(st, **state):
    """See Example on Multipage"""


def compute_page(st, **state):
    """See Example on Multipage"""


def landing_page(st):
    st.title("This is a Multi Page Application")
    st.write("Feel free to leave give a star in the Github Repo")


app = MultiPage()
app.st = st

app.add_app("Landing", landing_page, initial_page=True)
app.add_app("Input Page", input_page)
app.add_app("BMI Result", compute_page)

app.run()

Customization

There is additional functionality to customized the UI. In this example all the default text is replaced with custom messages.

import streamlit as st
from streamlit_multipage import MultiPage, save


def input_page(st, **state):
    """See Example on Multipage"""


def compute_page(st, **state):
    """See Example on Multipage"""


def landing_page(st):
    """See Example on Landing Page"""


def footer(st):
    st.write("Developed by [ELC](https://elc.github.io)")


def header(st):
    st.write("This app is free to use")


def sidebar(st):
    st.button("Donate (Dummy)")


app = MultiPage()
app.st = st

app.start_button = "Go to the main page"
app.navbar_name = "Other Pages:"
app.next_page_button = "Next Chapter"
app.previous_page_button = "Previous Chapter"
app.reset_button = "Delete Cache"
app.navbar_style = "SelectBox"

app.header = header
app.footer = footer
app.navbar_extra = sidebar

app.hide_menu = True
app.hide_navigation = True

app.add_app("Landing", landing_page, initial_page=True)
app.add_app("Input Page", input_page)
app.add_app("BMI Result", compute_page)

app.run()

Installation

No Install

This is a really simple script, if introducing new and small dependencies is not desired, simply copy and paste the content of the src folder into your project (one single file). Beware that this method does not include all the advantages of using a dependency such as updates, dependency tracking and so on.

Via Pip

Install by running

pip install streamlit-multipage

The only dependency is streamlit which should be already installed. It will be installed automatically if not present. Optionally, joblib can be installed if the pickle module cannot handle the object in the saved state.

Similar projects

Having multi page streamlit app is something many people try to achieve, therefore, many libraries were developed to achieved this goal. Some of them are listed below:

If this project does not fit your needs, please check these as well.

Maintainers

This project is maintained by Yan Almeida and Ezequiel Leonardo Castaño

Metadata

Release files for streamlit-multipage 0.0.18

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for streamlit-multipage 0.0.18
File Size Uploaded
streamlit-multipage-0.0.18.tar.gz 21.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for streamlit-multipage 0.0.18
File Interpreter ABI Platform
streamlit_multipage-0.0.18-py3-none-any.whl Python 3 none any Details

Total release size: 40.3 kB

Release files / streamlit-multipage-0.0.18.tar.gz

Download URL streamlit-multipage-0.0.18.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
698bc4af147c9d76a17ba0df286547c8e167255df08eb50e353349b606e74a11
BLAKE2b-256 checksum
How to use checksums
a5677fb1b44fb4db4d5589bb2570c90c6ade3d5136253ce65c9abd8aa534d7d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.63.0 importlib-metadata/4.11.2 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release files / streamlit_multipage-0.0.18-py3-none-any.whl

Download URL streamlit_multipage-0.0.18-py3-none-any.whl
Size 19.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a9a4da06c29ef312878b7ea968cc4f130a0f37c2f738b259a52885bddf18b78c
BLAKE2b-256 checksum
How to use checksums
30781439908daa1ea572a8b2b455d9d8ce95bd0f8390d0514224575212084c51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.63.0 importlib-metadata/4.11.2 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release history Release notifications | RSS feed

This release

0.0.18 This release

2 release files

0.0.17

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page