Having trouble developing a feature in my app, if anyone could please bring some insights.
I have an app with multiple pages, and each page has a form. While user navigates between pages, the form widgets (say with key “a”) keep their state in a different session state (say with key “page_a”).
When the original page is regenerated, each widget has its value loaded from the session state value. That is fine, but I also want to incorporate with the new bind parameter to enable URL sharing.
The problem arises as when I start a page the query_params doesn’t populate and the URL is empty.
My current workaround is to check whether we are switching back from another page, set the query parameters from the session state, initialize widget (so it has the stored session state value), then rerun the page with bind.
This works mostly, except on some widgets, for example, the date_input. Whenever I rerun the page, the URL collapses because it thinks that the new date is the default. However, it is not the default of the page, as I use session state to update value of widget, I initially initialise “page_a” with the default if it already doesn’t exist, this causes an issue since if this URL is shared, the default date is given to the receiver whereas the sharer is on their own date (recognised as a default)
Below is a short example of how my current app works. I’m not sure how to workaround this, any suggestions much appreciated.
Thank you in advance
import datetime as dt
import streamlit as st
# function that saves the widget value to the persistent session state value
def persist():
st.session_state["persist_across_page"] = st.session_state["widget"]
# mock page for switching
def other_page():
pass
# main page
def main_page():
# default date that is applied if no persistent session state value
default_date = dt.date(2026, 1, 1)
if "persist_across_page" not in st.session_state:
st.session_state["persist_across_page"] = default_date
# check whether coming back from a page swap (in which case, widget has never been initialized
initial_load = "widget" not in st.session_state
# add value to widget (either default OR what the session state orginally had
st.session_state["widget"] = st.session_state["persist_across_page"]
# populate query params (URL) if necessary
if initial_load:
st.query_params["widget"] = st.session_state["widget"]
with st.form(key="form"):
# create widget without bind initially as we've updated query params manually
# then create with bind so URL updates as user updates
st.date_input(
key="widget",
label="date",
bind="query-params" if not initial_load else None,
)
submit = st.form_submit_button(label="Submit", on_click=persist)
if submit:
# mock form submit
st.write(st.session_state["widget"])
if initial_load:
# re reun page if needed to regenerate bound widget
st.rerun()
st.navigation(
[st.Page(other_page),
st.Page(main_page)]
).run()