Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal/pop-up widget #1360

Closed
arraydude opened this issue Apr 17, 2020 · 121 comments · Fixed by #8040
Closed

Modal/pop-up widget #1360

arraydude opened this issue Apr 17, 2020 · 121 comments · Fixed by #8040
Labels
area:layout status:in-progress We're on it! type:enhancement Requests for feature enhancements or new features

Comments

@arraydude
Copy link
Contributor

arraydude commented Apr 17, 2020

Problem

As a user I would like to show some specific data within a modal

Solution

https://baseweb.design/components/modal/

Additional context

User question: #1337


Community voting on feature requests enables the Streamlit team to understand which features are most important to our users.

If you'd like the Streamlit team to prioritize this feature request, please use the 👍 (thumbs up emoji) reaction in response to the initial post.

Visits

@arraydude arraydude added the type:enhancement Requests for feature enhancements or new features label Apr 17, 2020
@andfanilo
Copy link
Contributor

This would be an interesting usecase.

I know if I had a Modal at hand, if possible I'd like to use it like I use the sidebar, that is enable Streamlit widgets inside a modal (button, file_uploader...).

That would require a bit of API design thinking though around composing what's inside the modal with different st calls inside, and managing enter/exit calls through a context manager.

quickly jotting an idea that really is just an idea without too much thinking:

df = None
with st.modal(label_ok_button, label_cancel_button) as m: 
    m.header("Hello world, input your file")
    f = m.file_uploader(...)
    while not f:
        m.markdown("Waiting for your input")
    df = process_file(f)

@moises-catala-sonosuite

This feature would be a great addition!

@satsumarc
Copy link

Also going to add that this would be hugely useful for some projects I'm working on. My use case is that the user is committing to sending an external API POST request, but needs a modal dialogue with a confirmation of what is about to be sent (a list of the variables prepared for the request), to ensure they are performing the correct action.

I'll add that perhaps this is veering a bit outside the scope of Streamlit as a whole, so understanadbly might not be where the focus should be for the team.

@durd07
Copy link

durd07 commented Dec 13, 2021

Hi,

Any update on this line?

@Mohammadabd
Copy link

Following...

@Sriram-bb63
Copy link

I would love to get this feature asap

@bbelescot
Copy link

bbelescot commented Jan 20, 2022

I think it'd be a killer feature! Following this :)

@danielhangan
Copy link

I also needed this feature but I found a temporary workaround using st.expander()

modal = st.expander("Advanced options")

option_1 = modal.checkbox("Option 1")
option_2 = modal.checkbox("Option 2")
option_3 = modal.checkbox("Option 3")
option_4 = modal.checkbox("Option 4")

if option_1:
   st.write("Hello world 1")

if option_2:
   st.write("Hello world 2")

if option_3:
   st.write("Hello world 3")

if option_4:
   st.write("Hello world 4")

@ro1and
Copy link

ro1and commented Jan 28, 2022

Following as well! This would be a really nice addition to Streamlit

@tyrin
Copy link

tyrin commented Feb 7, 2022

This feature would be super useful in a bunch of use cases:

  • legend information
  • "how do I use/interpret this graph" help for new users
  • popups from within visualizations

@abedhammoud
Copy link

It would be a great feature to have! Thank you for the excellent work you have done already!

@oliverfunk
Copy link

Would be a great feature! Could show warning dialogs etc.

@andfanilo
Copy link
Contributor

In the meantime you could try the modal example in the experimental section of the Hydralit Components repo by @TangleSpace

image

image

Have a nice day,
Fanilo

@corticalstack
Copy link

@andfanilo had a look at the example modal popup from the hydralit package, could'nt see if tehre's a way to pass in id or other identifier should there be multipel buttons (say in a list) that potentially can call the popup?

@lhlong
Copy link

lhlong commented Jun 6, 2022

how's this going on?

@PvanHengel
Copy link

Agree this is a great feature request, where can we find a list of all features and vote them up down? This one belongs at the top!

@andfanilo
Copy link
Contributor

There's a roadmap here: https://share.streamlit.io/streamlit/roadmap/
But I think the thumbs up counter for the issue on the first message is part of what the team considers to prioritize, alongside other more internal stuff.
Fanilo

@MrDebugger
Copy link

Following 🥶

@naorpeled
Copy link

naorpeled commented Aug 11, 2022

Would love to help with this if needed 🙏

@littleK0i
Copy link

Following as well.

@carolinedlu carolinedlu changed the title Modal / Popup widget Modal/pop-up widget Nov 10, 2022
@Behordeun
Copy link

I am looking forward to the release of the pop-up feature. It will be a great one for all users.

raethlein added a commit that referenced this issue Apr 11, 2024
<!--
⚠️ BEFORE CONTRIBUTING PLEASE READ OUR CONTRIBUTING GUIDELINES!
https://github.com/streamlit/streamlit/wiki/Contributing
-->

## Describe your changes

Closes #1360

This PR adds a dialog layout container. This is exposed to users via the
`@st.experimental_dialog`
decorator. A function decorated with this decorated will render a dialog
when being called. The body of the decorated function will be rendered
as the dialog's content.
It uses the fragment decorator (introduced in
#8343) under the hood so that
the dialog can be interacted with without triggering a full-app rerun.

Example:
```python
import streamlit as st

@st.experimental_dialog("Streamlit Example Dialog")
def example_dialog(some_arg: str, some_other_arg: int):
    st.write(f"You passed following args: {some_arg} | {some_other_arg}")
    # interacting with the text_input only re-runs `example_dialog`
    some_text_input = st.text_input("Type something:", key="example_dialog_some_text_input")
    # following write is updated when chaning the text_input inside the dialog
    st.write(f"You wrote '{some_text_input}' in the dialog")
    if st.button("Close the dialog"):
        st.rerun()

if st.button("Open dialog"):
    example_dialog("Some string arg", 42)

# following write is updated with the dialog's text input when the dialog was opened, the text input was interacted with and a re-run was triggered, e.g. by clicking the Close-button defined in `example_dialog`
st.write(f"You wrote '{st.session_state.get('example_dialog_some_text_input', '')}' in the dialog")
```

![Screenshot 2024-04-04 at 16 31
35](https://github.com/streamlit/streamlit/assets/3775781/751a43d1-7c6a-4642-8864-d08a5d286cb5)


Since it uses the experimental fragment feature, it is exposed as
experimental as well for now.

## GitHub Issue Link (if applicable)

## Testing Plan

- Added Python and JavaScript unit tests
- Added e2e playwright tests

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.
@jrieke
Copy link
Collaborator

jrieke commented Apr 11, 2024

This is finally merged and will be released in 1.34 in early May! You should also be able to test this with pip install streamlit-nightly starting tomorrow. Let us know here if you find any issues!

@jrieke jrieke changed the title [Coming soon] Modal/pop-up widget Modal/pop-up widget Apr 14, 2024
@jrieke jrieke unpinned this issue Apr 14, 2024
@sfc-gh-pkommini
Copy link

sfc-gh-pkommini commented Apr 15, 2024

@jrieke: Is there a way to do a rerun on x-button click or on esc key hit?

Our use case is as follows:

  1. We use the pop up to display a form with some drop downs where user selects some options
  2. Once the user submits the form_submit_button, we execute a Snowpark query to update backend data
  3. Once the query is successfully executes we display a success message
  4. On seeing the message we expect the user to close the dialog (We don't automatically close because we want the user to really see and digest the success message)
  5. At this point we want our results on the home screen refreshed with the new results after the updates from the 2.

For this we need to be able to use the x-button submit. Is there a workaround for this use case? Since I have a form in the dialog I can't introduce a second button that executes a rerun, hence my ask to be able to capture the x-button click in st.session_state.

@swagluke
Copy link

@jrieke
Thanks for the update. I've tried to uninstall streamlit and reinstall steamlit-nightly to test out this feature. But it's still showing me that "streamlit" has no attribute 'dialog'. Anyone else having issues?

pip uninstall streamlit
pip install streamlit-nightly --upgrade

@sfc-gh-pkommini
Copy link

I had no issues using it.

@swagluke
Copy link

@sfc-gh-pkommini
Thanks for the info. I suspect my installation is messed up.
Once you pip install streamlit-nightly, are you able to verify it's version using
streamlit --version?

@sfc-gh-pkommini
Copy link

sfc-gh-pkommini commented Apr 15, 2024

I'm using a docker container and I just replaced streamlit with streamlit-nightly in my requirements.txt and then used the st.experimental_dialog

@swagluke
Copy link

swagluke commented Apr 15, 2024

@sfc-gh-pkommini
This is helpful.
In your python file,

  1. Did you import streamlit as st?
  2. Is it st.dialog or st.experimental_dialog?

@jrieke
Copy link
Collaborator

jrieke commented Apr 15, 2024

@sfc-gh-pkommini Ah, this is not possible today. Can you open a new feature request on GitHub for this, so it doesn't get lost in here? I also have a few more comments on your use case but will add them to the new issue.

@swagluke It's st.experimental_dialog. It should actually work by uninstalling streamlit and installing streamlit-nightly. Can you make sure it's properly uninstalled, e.g. by trying to import streamlit somewhere and checking that it doesn't work? Or maybe pip is using some cached version of streamlit for installation?

@swagluke
Copy link

@jrieke
Not sure what happens, I used the same process to uninstall streamlit and reinstall streamlight-nightly. Now it's working.
pip is indeed weird.
Thanks for the quick response.

@ToshiNandanReddy
Copy link

@jrieke The show dialog collapses the file upload option sometimes when I am writing the missing columns
is there any work around for this?

this is my code

def show_dialog():
missing_columns = []
upload = st.file_uploader("Upload a file")
,button, = st.columns([0.3,0.4,0.3])
with button:
if st.button("Read File", use_container_width = True):
st.session_state.uploaded_file_encounters = pd.read_csv(upload)
columns_list = st.session_state.uploaded_file_encounters.columns.tolist()
if "Ineligible Visit Type" not in columns_list:
missing_columns.append("Ineligible Visit Type")

        if "Ineligible NPI" not in columns_list:
            missing_columns.append("Ineligible NPI")
            
        if len(missing_columns) == 0:
            st.write("All required columns are present in the uploaded file")
            
if len(missing_columns) > 0:
    st.write("Missing Columns from the uploaded file:")
    st.write(missing_columns)
    
if st.button("Data Verified",use_container_width = True):
    close_dialog()

def close_dialog():
st.experimental_rerun()

zyxue pushed a commit to zyxue/streamlit that referenced this issue Apr 16, 2024
## Describe your changes

This PR adds a popover layout container. It consists of a button-like
element and a container that opens when the button is clicked, e.g.:

```python
with st.popover( "Open popover"):
    st.markdown("Hello World 👋")
    st.text_input("Whats your name?")
```

<img width="434" alt="image"
src="https://github.com/streamlit/streamlit/assets/2852129/ec891bc1-8556-4db7-be3f-d8b226e15365">

Demo: https://popover-container-demo.streamlit.app/

## GitHub Issue Link (if applicable)

Solves some of the usecases discussed in
streamlit#1360

## Testing Plan

- Added unit and e2e tests

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.
@swagluke
Copy link

Follow-up question here,
I'm using streamlit-authenticator and the newest streamlit-nightly. But putting both of them in the requirements.tx to create docker image. For some reason, it triggers streamlit to be installed since streamlit is a dependency of streamlit-authenticator. Then I guess it overwrites streamlit-nightly.
Anyone has experience dealing with it?

@pri2si17-1997
Copy link

pri2si17-1997 commented Apr 19, 2024

Has anyone tried experimental_dialog with chat_input. It's failing for me when I try to submit message.

RuntimeError: Could not find fragment with id <FRANGMENT_ID>

@raethlein
Copy link
Collaborator

Has anyone tried experimental_dialog with chat_input. It's failing for me when I try to submit message.

RuntimeError: Could not find fragment with id <FRANGMENT_ID>

@LukasMasuch I am wondering whether this might be related to / fixed by #8533

@LukasMasuch
Copy link
Collaborator

Probably not :( is this happening whenever chat_input submits a message in an experimental_dialog?

@swagluke
Copy link

Follow-up question here, I'm using streamlit-authenticator and the newest streamlit-nightly. But putting both of them in the requirements.tx to create docker image. For some reason, it triggers streamlit to be installed since streamlit is a dependency of streamlit-authenticator. Then I guess it overwrites streamlit-nightly. Anyone has experience dealing with it?

Would love to get some suggestions on this. Thanks in advance.

@Stefano97
Copy link

Stefano97 commented Apr 24, 2024

Hi ! Great feature ! I am running in python 3.11 and nightly version installed but the st.rerun() does not close the dialog for me when clicking Cancel (only when clicking Delete). This seems strange because I see the page refreshing in the background. Here is the code I am using (taken from example and adapted a little to my usecase):

@st.experimental_dialog("Delete existing user")
def delete_user_dialog(self, user_to_delete):
    username = user_to_delete["name"]
    st.write(f"Are you sure you want to delete {username}?")

    col1, col2 = st.columns([1, 1])
    if col1.button("Delete"):
        self.perform_deletion_user(user_to_delete)
        st.rerun()

    if col2.button("Cancel"):
        st.rerun()

This very behaviour does not happen when I bind it to a button, but actually I would love to use it inside a on_change function for a data editor. (maybe there is another way of closing the dialog)

@dilipthakkar-metacube
Copy link

dilipthakkar-metacube commented Apr 26, 2024

Hi Team,
I'm very excited to use this feature. However with the streamlit-nightly I'm facing some issues. I want to create a feature in which I have a cancel button and on click of that cancel button I want to open a dialog with "Yes" & "No" buttons. However when I'm calling the dialog function in a button callback then I'm getting an error (Could not find fragment with id 1c78f2182f4bcfbd2cda9b9971306dc7) while clicking "Yes" or "No" button.
Following is my code snippet.

import streamlit as st

@st.experimental_dialog("Are you sure you want cancel changes?")
def show_dialog():
    def on_click_yes():
        print("yes")
        st.rerun()
        
    def on_click_no():
        print("No")
        st.rerun()
        
    cols = st.columns(2)
    with cols[0]:
        st.button("No", on_click=on_click_no)
    with cols[1]:
        st.button("Yes", on_click=on_click_yes)
         

st.button("Cancel", key="sample_key", on_click=show_dialog)

@dilipthakkar-metacube
Copy link

Also, can we make it flexible to not pass the "title" in the dialog, as we can pass a key to the dialog to identify it but the mandatory title is forcing me to show some title on UI.

@raethlein
Copy link
Collaborator

Hi ! Great feature ! I am running in python 3.11 and nightly version installed but the st.rerun() does not close the dialog for me when clicking Cancel (only when clicking Delete). This seems strange because I see the page refreshing in the background. Here is the code I am using (taken from example and adapted a little to my usecase):

@st.experimental_dialog("Delete existing user")
def delete_user_dialog(self, user_to_delete):
    username = user_to_delete["name"]
    st.write(f"Are you sure you want to delete {username}?")

    col1, col2 = st.columns([1, 1])
    if col1.button("Delete"):
        self.perform_deletion_user(user_to_delete)
        st.rerun()

    if col2.button("Cancel"):
        st.rerun()

This very behaviour does not happen when I bind it to a button, but actually I would love to use it inside a on_change function for a data editor. (maybe there is another way of closing the dialog)

@Stefano97 would you be able to share the full code for this? I tried to add your code into a sample app and do not have any issues.

@raethlein
Copy link
Collaborator

raethlein commented Apr 26, 2024

import streamlit as st

@st.experimental_dialog("Are you sure you want cancel changes?")
def show_dialog():
    def on_click_yes():
        print("yes")
        st.rerun()
        
    def on_click_no():
        print("No")
        st.rerun()
        
    cols = st.columns(2)
    with cols[0]:
        st.button("No", on_click=on_click_no)
    with cols[1]:
        st.button("Yes", on_click=on_click_yes)
         

st.button("Cancel", key="sample_key", on_click=show_dialog)

Interesting use-case! The issue seems to come from the fact that the dialog (fragment) is called via the callback. If you refactor that to

 if st.button("Cancel", key="sample_key"):
  show_dialog()

it should work (actually you will see a warning that st.rerun is not allowed to be called from a callback, so that needs to be refactored too).

Thanks for the feedback, we are going to discuss this with the team!

@raethlein
Copy link
Collaborator

Has anyone tried experimental_dialog with chat_input. It's failing for me when I try to submit message.

RuntimeError: Could not find fragment with id <FRANGMENT_ID>

Hey @pri2si17-1997 , I tried to reproduce it but the following example app works fine for me:

import streamlit as st

st.title("Echo Bot")

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

@st.experimental_dialog("Echo Chat")
def open_chat_dialog():
    chat_messages = st.container()
    # Display chat messages from history on app rerun
    for message in st.session_state.messages:
        with chat_messages.chat_message(message["role"]):
            st.markdown(message["content"])

    # React to user input
    if prompt := st.chat_input("What is up?"):
        # Display user message in chat message container
        chat_messages.chat_message("user").markdown(prompt)
        # Add user message to chat history
        st.session_state.messages.append({"role": "user", "content": prompt})

        response = f"Echo: {prompt}"
        # Display assistant response in chat message container
        with chat_messages.chat_message("assistant"):
            st.markdown(response)
        # Add assistant response to chat history
        st.session_state.messages.append({"role": "assistant", "content": response})

if st.button("Open chat"):
    open_chat_dialog()

Could you share your code so that we can have a look?

@jrieke
Copy link
Collaborator

jrieke commented Apr 26, 2024

Also, can we make it flexible to not pass the "title" in the dialog, as we can pass a key to the dialog to identify it but the mandatory title is forcing me to show some title on UI.

@dilipthakkar-metacube, can you describe or, even better, share a screenshot of your use case so I can see what you're trying to do? The issue with removing the title/making it optional is that we still have to show the X on the top right, so we'd either have a big blank space at the top of the dialog or have the X button and elements overlap, if there's no title.

@dilipthakkar-metacube
Copy link

Hi @raethlein , It would be great if we would be able to call the fragment from a callback and we really need this feature in one of our production level application which is built top on streamlit.

Let me explain the exact use case: We have a custom streamlit component which has a button which is bind to a python callback. And on the click of that button we want to show a modal box to users to confirm the changes and provide some other information also.

It would be great help if you will consider this request. Thank you for giving us one of the best tool to create web applications with less code.

@jrieke
Copy link
Collaborator

jrieke commented Apr 29, 2024

@dilipthakkar-metacube can you open a new GitHub issue as a feature request for this use case? In here it will only get lost since the issue is already closed. We've been thinking about how to make confirmation dialogs/buttons even easier to use, so would be very happy to hear about your use case in detail on the new issue and see what others think!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:layout status:in-progress We're on it! type:enhancement Requests for feature enhancements or new features
Projects
None yet
Development

Successfully merging a pull request may close this issue.