How to open st.dialog from a streamlit-echarts event without full page rerun?

Hi everyone,

I’m working on trying to improve the opening of st.dialog from a chart interaction.

I’m using streamlit-echarts, and I can receive the chart event normally. For example, when the user double-clicks a chart item, I get the event data back in Python.

The pattern I’m using today is basically this:

event = st_echarts(
    options=options,
    events={
        "dblclick": """
            function(params) {
                return {
                    name: params.name,
                    value: params.value
                };
            }
        """
    },
    key="my_chart",
)

if event and event.chart_event:
    st.session_state["pending_dialog"] = event.chart_event
    st.rerun()

Then, later in the script, I open the dialog:

pending = st.session_state.pop("pending_dialog", None)

if pending:
    show_dialog(pending)

Functionally this works, but the UX is not great. Since I need to call st.rerun(), the whole dashboard reruns and the charts visibly reload before the dialog opens.

I also tried opening the dialog directly when the ECharts event is received:

if event and event.chart_event:
    show_dialog(event.chart_event)

In my real dashboard, opening the dialog directly from the ECharts event is not as clean as in a minimal example. The page has charts, @st.fragment sections, and custom metric components. When I open the dialog directly, some sections/components can rerender or visually shift, and chart tooltips can remain visible until the next st.rerun(). So the interaction works, but the page feels visually unstable.

The session_state + st.rerun() pattern is more stable, but it causes the whole dashboard to visibly reload before the dialog opens.

So my question is: what is the recommended pattern for this case? Should dialogs triggered by custom component events generally be opened through session_state + st.rerun(), or is there a cleaner way to open st.dialog from a streamlit-echarts event without a visible full dashboard rerun?

I’m using Streamlit 1.60.0 with Python 3.11, running locally and on a private server. There’s no Python exception; this is mainly a UX/rendering issue.

Thanks!

Welcome to the community and thanks for your thoughtful question! :balloon: My understanding is that, due to Streamlit’s execution model, there isn’t a built-in way to open an st.dialog from a custom component event (like a chart double-click) without a full script rerun or some visible UI shift. The session_state + st.rerun() pattern you’re using is the most robust and recommended approach for synchronizing dialog state with the rest of your app, especially when your dashboard has multiple charts, fragments, or custom components. This is consistent with best practices discussed in the Streamlit forums and the official docs.

Unfortunately, Streamlit currently doesn’t support partial reruns for custom component events outside of fragments or forms, so any dialog triggered by a chart event will require a rerun to update the UI cleanly. Using session_state as a flag and calling st.rerun() ensures the dialog opens in a stable state, even if it causes a brief reload. There’s no documented alternative for opening dialogs from custom component events without a rerun or UI flicker, and this limitation is a known tradeoff in Streamlit’s app model. If you’d like to see more granular rerun control, consider upvoting or filing a feature request on the Streamlit GitHub.

Sources:

Open the dialog at the end of the script. If the dialog captures deps then save those in SS and do a rerun.

Thanks. That is exactly the pattern I described as my current workaround.

The issue I’m asking about is the visible full-app rerun before the dialog opens. Is there any supported way to avoid that, or is this currently unavoidable with custom component events?

I’m suggesting putting this at the end of the script.