如何在Streamlit的st.markdown中点击HTML按钮触发st.dialog弹窗
解决方案:通过JS+隐藏组件实现HTML按钮触发Streamlit Dialog
要实现st.markdown中的HTML按钮触发st.dialog,核心是解决前端HTML事件与后端Streamlit状态同步的问题(因为HTML按钮无法直接调用Python函数)。以下是可行的实现方案:
实现思路
- 用会话状态变量
show_dialog控制弹窗的显示/隐藏 - 新增一个隐藏的Streamlit文本输入组件,作为前后端交互的桥梁
- 给HTML按钮添加JS点击事件,修改隐藏输入框的值并触发输入事件,触发后端回调更新会话状态
- 根据会话状态决定是否显示弹窗
完整代码
import streamlit as st # 初始化会话状态,控制弹窗显示 if "show_dialog" not in st.session_state: st.session_state.show_dialog = False # 回调函数:当隐藏输入值变化时,更新弹窗状态 def trigger_dialog(): if st.session_state.hidden_trigger == "open_dialog": st.session_state.show_dialog = True # 重置触发值,避免重复触发 st.session_state.hidden_trigger = "" # 隐藏的文本输入组件(仅作为交互桥梁) st.text_input( label="", key="hidden_trigger", on_change=trigger_dialog, label_visibility="hidden", disabled=False ) # 定义弹窗内容 @st.dialog("POP UP WINDOW") def show_rgpd_popup(): st.write("This is pop up window") # 关闭弹窗时重置状态 if st.button("关闭"): st.session_state.show_dialog = False st.rerun() # 根据会话状态显示弹窗 if st.session_state.show_dialog: show_rgpd_popup() # 渲染HTML按钮(保留st.markdown方式) st.markdown(""" <div class="navbar-buttons"> <a href="javascript:void(0)" onclick=" // 定位到隐藏的文本输入框 const hiddenInput = document.querySelector('[data-testid=\"stTextInput\"] input'); // 设置触发值并触发输入事件,触发后端回调 hiddenInput.value = 'open_dialog'; hiddenInput.dispatchEvent(new Event('input')); " class="navbar-text">POP UP BUTTON</a> </div> """, unsafe_allow_html=True) st.title("TEST JS & HTML IN STREAMLIT") st.caption('A live demo')
关键细节说明
- 隐藏组件的作用:Streamlit的组件状态变化会自动触发后端重新运行,因此用隐藏的
st.text_input作为中间层,让JS可以通过修改它的值来通知后端更新状态 - JS事件处理:
javascript:void(0)避免点击链接时页面跳转,dispatchEvent(new Event('input'))模拟用户输入,确保Streamlit能捕获到值的变化 - 状态重置:弹窗关闭时调用
st.rerun()刷新页面,确保状态同步
内容的提问来源于stack exchange,提问作者stat_man




